Merge branch 'master' of https://codefirst.iut.uca.fr/git/noan.randon/Favor
continuous-integration/drone/push Build was killed Details

master
Zakariya SAOULA 2 years ago
commit 554b75c3cc

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions">
<TaskOptions isEnabled="true">
<option name="arguments" value="$FileName$:$FileNameWithoutExtension$.css" />
<option name="checkSyntaxErrors" value="true" />
<option name="description" />
<option name="exitCodeBehavior" value="ERROR" />
<option name="fileExtension" value="sass" />
<option name="immediateSync" value="true" />
<option name="name" value="Sass" />
<option name="output" value="$FileNameWithoutExtension$.css:$FileNameWithoutExtension$.css.map" />
<option name="outputFilters">
<array />
</option>
<option name="outputFromStdout" value="false" />
<option name="program" value="sass" />
<option name="runOnExternalChanges" value="true" />
<option name="scopeName" value="Project Files" />
<option name="trackOnlyRoot" value="true" />
<option name="workingDir" value="$FileDir$" />
<envs />
</TaskOptions>
</component>
</project>

@ -2,12 +2,28 @@ import axios from "axios";
import { setPostError } from "../reducers/error.reducer";
import { setPostData, setPostLikeData, setPostUnLikeData } from "../reducers/post.reducer";
export const getPosts = () => {
export const getPosts = (num) => {
return (dispatch) => {
return axios
.get(`${process.env.REACT_APP_API_URL}api/post/`)
.then((res) => {
dispatch(setPostData(res.data));
let array = res.data.slice(0, num);
dispatch(setPostData(array));
})
.catch((err) => console.log(err))
}
}
export const getPostsDisc = (num) => {
return (dispatch) => {
return axios
.get(`${process.env.REACT_APP_API_URL}api/post/`)
.then((res) => {
console.log("test");
let array = res.data.sort((a, b) => b.likers.length - a.likers.length);
array = array.slice(0, num);
console.log(array);
dispatch(setPostData(array));
})
.catch((err) => console.log(err))
}
@ -48,11 +64,11 @@ export const addPost = (data) => {
.post(`${process.env.REACT_APP_API_URL}api/post/`, data)
.then((res) => {
console.log(data,"test");
// if (res.data.errors) {
// dispatch(setPostError({payload: res.data.errors }));
// } else {
// dispatch(setPostError({payload: "" }));
// }
if (res.data.errors) {
dispatch(setPostError({payload: res.data.errors }));
} else {
dispatch(setPostError({payload: "" }));
}
});
};
};
@ -85,48 +101,48 @@ export const addPost = (data) => {
// };
// };
// export const addComment = (postId, commenterId, text, commenterPseudo) => {
// return (dispatch) => {
// return axios({
// method: "patch",
// url: `${process.env.REACT_APP_API_URL}api/post/comment-post/${postId}`,
// data: { commenterId, text, commenterPseudo },
// })
// .then((res) => {
// dispatch({ type: ADD_COMMENT, payload: { postId } });
// })
// .catch((err) => console.log(err));
// };
// };
// export const editComment = (postId, commentId, text) => {
// return (dispatch) => {
// return axios({
// method: "patch",
// url: `${process.env.REACT_APP_API_URL}api/post/edit-comment-post/${postId}`,
// data: { commentId, text },
// })
// .then((res) => {
// dispatch({ type: EDIT_COMMENT, payload: { postId, commentId, text } });
// })
// .catch((err) => console.log(err));
// };
// };
export const addComment = (postId, commenterId, text, commenterPseudo) => {
return (dispatch) => {
return axios({
method: "patch",
url: `${process.env.REACT_APP_API_URL}api/post/comment-post/${postId}`,
data: { commenterId, text, commenterPseudo },
})
.then((res) => {
// dispatch({ type: ADD_COMMENT, payload: { postId } });
})
.catch((err) => console.log(err));
};
};
// export const deleteComment = (postId, commentId) => {
// return (dispatch) => {
// return axios({
// method: "patch",
// url: `${process.env.REACT_APP_API_URL}api/post/delete-comment-post/${postId}`,
// data: { commentId },
// })
// .then((res) => {
// dispatch({ type: DELETE_COMMENT, payload: { postId, commentId } });
// })
// .catch((err) => console.log(err));
// };
// };
export const editComment = (postId, commentId, text) => {
return (dispatch) => {
return axios({
method: "patch",
url: `${process.env.REACT_APP_API_URL}api/post/edit-comment-post/${postId}`,
data: { commentId, text },
})
.then((res) => {
// dispatch({ type: EDIT_COMMENT, payload: { postId, commentId, text } });
})
.catch((err) => console.log(err));
};
};
export const deleteComment = (postId, commentId) => {
return (dispatch) => {
return axios({
method: "patch",
url: `${process.env.REACT_APP_API_URL}api/post/delete-comment-post/${postId}`,
data: { commentId },
})
.then((res) => {
//dispatch({ type: DELETE_COMMENT, payload: { postId, commentId } });
})
.catch((err) => console.log(err));
};
};
// export const getTrends = (sortedArray) => {
// return (dispatch) => {
// dispatch({ type: GET_TRENDS, payload: sortedArray });

@ -13,8 +13,6 @@ export const getUser = (uid) => {
};
};
export const uploadPicture = (data, id) => {
return (dispatch) => {
return axios
@ -22,7 +20,7 @@ export const uploadPicture = (data, id) => {
.then((res) => {
return axios
.get(`${process.env.REACT_APP_API_URL}api/user/${id}`)
.then((res) => {
.then((res) => {
dispatch(setUserDataImg(res.data.picture));
})
})
@ -58,4 +56,6 @@ export const unFollowUser = (followerId, idToUnFollow) => {
})
.catch((err) => console.log(err));
};
};
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

@ -1,26 +1,63 @@
import React from 'react';
import { NavLink } from "react-router-dom";
import { NavLink } from "react-router-dom";
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
/*import PolitiqueDeConfidentialite from '../components/';
*/
const ConfigurationDuCompte =()=>{
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [controlPassword, setControlPassword] = useState('');
return(
<div>
<h2>Modifucation information du compte</h2>
<div className='ligneHorizontal'>
<div>
<span>adresse mail : mail</span>
<span>mot de passe : mdp</span>
<span>confirmer le mot de passe : mdp</span>
<h2 className='ligneHorizontal'>Modification des information du compte</h2>
<form className="ModifucationInformationDuCompte">
<div className='ModificationInformationDuCompteText alignementText'>
<span>email</span>
<span>mot de passe</span>
<span>comfirmation mot de passe</span>
</div>
<div>
<div className='ModificationInformationDuCompteText'>
<input type="text"
name="email"
id="email"
onChange={(e) => setEmail(e.target.value)}
value={email}/>
<br />
<div className='email error'></div>
<input type="password"
name="password"
id="password"
onChange={(e) => setPassword(e.target.value)}
value={password}/>
<br/>
<div className='password error'></div>
<input type="password"
name="password"
id="password-conf"
onChange={(e) => setControlPassword(e.target.value)}
value={controlPassword}/>
<div className='password error'></div>
</div>
<button className='buttonValidationChangements'>Valider</button>
</div>
</div>
<h2>Suppression du compte</h2>
<div className='ligneHorizontal'/>
<div >
</form>
<div />
<h2 className='ligneHorizontal'>Suppression du compte</h2>
<div className='buttonSuppressionCompte'>
<button>
supprimer votre compte
</button>
<span>gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg</span>
<p className='buttonSuppressionText'>Note : action irreversible qui vous fera perdre toutes les données du compte en conséquence</p>
</div>
</div>
)

@ -1,51 +1,169 @@
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import { useSelector, useDispatch } from 'react-redux';
import PP from "../../assets/img/unknown.png";
import PLUS from "../../assets/img/plus.png";
import { NavLink } from "react-router-dom";
import axios from "axios";
import { uploadPicture } from '../../actions/user.actions';
const ConfigurationDuProfil = ()=>{
const userData = useSelector((state) => state.userReducer)
return(
const userData = useSelector((state) => state.user.user);
const [pseudo, setPseudo] = useState(userData.pseudo);
const[userPicture, setUserPicture] = useState(userData.picture);
const [tmpImage, setTmpImage] =useState(PLUS);
const [displayAdd, setDisplayAdd] = useState(false);
const dispatch = useDispatch();
const handleValidationPopup =(e)=>{
setUserPicture(tmpImage);
setDisplayAdd(false);
}
const handleLoadFile=(e)=>{
const file=e.target.files[0];
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
setTmpImage({
data: reader.result,
contentType: file.type,
});
};
};
const handleTPM =()=> {
console.log("test");
console.log(tmpImage);
}
const handleUpdate = async (e) => {
console.log(userPicture)
e.preventDefault();
const data = new FormData();
data.append("pseudo", pseudo);
data.append("userId", userData._id);
data.append("file",userPicture);
dispatch(uploadPicture(data,userData._id));
//const pseudoError = document.querySelector(".pseudo.error");
/* const pictureError =document.querySelector(".picture.error");
await axios({
method: "post",
url: `${process.env.REACT_APP_API_URL}api/user/upload`,
data: {
// pseudo,
userPicture,
}
,
})
.then((res) => {
console.log(res);
if (res.data.errors) {
//pseudoError.innerHTML = res.data.errors.pseudo;
pictureError.innerHTML = res.data.errors.picture;
}
})
.catch((err) => console.log(err));*/
};
return(
<div className='modificationDuProfilBackgroud'>
<h2 className='ligneHorizontal' >Modifucation du Profil</h2>
<h2 className='ligneHorizontal' >Modification des informations du Profil</h2>
<form action='' onSubmit={handleUpdate} >
<div className='modificationDuProfil' >
<img src={PP} className="imageDeProfil"/>
<>
<button className='imageDeProfilConfigurationPlus imageDeProfil' >
<img src={PLUS} className="plusButton "/>
<img src={userPicture} className="imageDeProfilConfiguration imageDeProfil" onClick={() => setDisplayAdd(true)}/>
</button>
<div className='picture error'></div>
</>
<div className='modificationDuProfilText alignementText'>
<span>Pseudo: </span>
<div className='modificationDuProfilText'>
<div className="inputbox">
<input
type="pseudo"
name="pseudo"
id="pseudo"
value={userData.pseudo}
onChange={(e) => setPseudo (e.target.value)}
/>
</div>
<div>
<div className='modificationDuProfilText'>
<input className='inputConfiguration'
type="pseudo"
name="pseudo"
id="pseudo"
value={pseudo}
onChange={(e) => setPseudo (e.target.value)}
/>
{/* <div className='pseudo error'></div>*/}
</div>
<div className="inputbox">
<span>Nom d'utilisateur</span>
<input
type="nomUtilisateur"
name="nomUtilisateur"
id="nomUtilisateur"
onChange={(e) => setNomUtilisateur (e.target.value)}
value={userData.pseudo}
/>
</div>
</div>
<button type='submit' className='buttonValidationChangements' id='update' value='update' >Valider</button>
</div>
</div>
</form>
<h2 className='ligneHorizontal' >Acces au dossiers personnel</h2>
<div className='accesDossiersPerso'>
<input type="checkbox" id="accesDossiersPerso" name='cocher' />
<label for="cocher">Cocher si oui</label>
<div className='accesDossiersPersoValidation'>
<input type="checkbox" name='cocher' />
<label for="cocher" className='textAccesDossiersPerso'>Cocher si oui</label>
</div>
</div>
{displayAdd && (
<div className='popup-modificationProfil'>
<div className="modal">
<div className='imagesPopup'>
<div className='imageModifSpace'>
<img src={userPicture} className=" imageDeProfil "/>
</div>
<div className='profile-pic '>
<label className="-label" for="file">
<span className="camera"></span>
<span>Changer</span>
</label>
<input type="file" id="file" name='file' accept=".jpg, .jpeg, .png" onChange={handleLoadFile}/> {/*onChange={handleLoadFile} onChange={(e)=> setTmpImage(e.target.files[0].name)} */}
<img src={tmpImage} className="imageDeProfil"id="output" />
</div>
</div >
<div className='buttonPopup'>
<button onClick={()=>setDisplayAdd(false)}>Retour</button>
<button onClick={handleTPM()} >Valider</button>
</div>
</div>
</div>
)}
</div>
)
}
export default ConfigurationDuProfil;
export default ConfigurationDuProfil;

@ -4,17 +4,21 @@ import { NavLink } from "react-router-dom";
const PolitiqueDeConfidentialite =()=>{
return(
<div>
Cette politique de confidentialité sapplique au site : Designed By GG.
La présente politique de confidentialité a pour but dexposer aux utilisateurs du site :
La manière dont sont collectées et traitées leurs données à caractère
personnel. Doivent être considérées comme données personnelles toutes les données étant susceptibles didentifier un utilisateur. Il sagit notamment du prénom et du nom, de lâge, de ladresse postale, ladresse mail, la localisation de lutilisateur ou encore son adresse IP ;
Quels sont les droits des utilisateurs concernant ces données ;
Qui est responsable du traitement des données à caractère personnes
collectées et traitées ;
A qui ces données sont transmises ;
Eventuellement, la politique du site en matière de fichiers cookies
<div className='PolitiqueDeConfidentialiteText'>
<p>La politique de confidentialité de notre réseau social est conçue pour vous informer sur les types d'informations que nous collectons, comment elles sont utilisées et protégées, et les choix que vous pouvez faire en ce qui concerne la collecte, l'utilisation et la divulgation de vos informations.</p>
<p>Nous collectons des informations vous concernant lorsque vous utilisez notre réseau social, y compris les informations de compte, les informations de profil, les informations de contenu, les informations de localisation, les informations de connexion et les informations de communication. Nous utilisons ces informations pour fournir et améliorer nos services, personnaliser votre expérience, communiquer avec vous, et pour d'autres fins autorisées par la loi.</p>
<p>Nous ne vendons ni ne partageons vos informations personnelles avec des tiers à des fins commerciales sans votre consentement. Nous pouvons cependant partager des informations avec des partenaires de confiance pour des raisons telles que la fourniture de services, la conformité aux exigences légales, et la protection de nos utilisateurs et de notre réseau social.</p>
<p>Vous pouvez contrôler les informations que vous partagez sur notre réseau social en modifiant les paramètres de votre compte. Vous pouvez également choisir de ne pas recevoir de communications marketing de notre part en suivant les instructions de désinscription incluses dans ces communications.</p>
<p>Nous prenons des mesures pour protéger vos informations contre l'accès non autorisé, l'utilisation, la modification, la divulgation ou la destruction. Ces mesures comprennent des contrôles physiques, électroniques et administratifs pour protéger les informations stockées sur nos systèmes.</p>
<p>Si vous avez des questions ou des préoccupations concernant notre politique de confidentialité, veuillez nous contacter à l'adresse e-mail indiquée sur notre site web. Nous nous réservons le droit de modifier cette politique de temps à autre et vous invite à consulter régulièrement cette page pour rester informé de tout changement.</p>
<p>En utilisant notre réseau social, vous acceptez les termes de cette politique de confidentialité.</p>
</div>
)

@ -40,27 +40,28 @@ const Connexion = (props) => {
<form className='cadre' action='' onSubmit={handleLogin} id="sign-up-form">
<h1>Connexion</h1>
<div className='inputbox'>
<span>email</span>
<input
type="text"
name="email"
id="email"
onChange={(e) => setEmail (e.target.value)}
value={email}/>
<span>email</span>
<div className="email error"></div>
</div>
<div className="email error"></div>
<br />
<div className="inputbox">
<span>mot de passe</span>
<input
type="password"
name="password"
id="password"
onChange={(e) => setPassword (e.target.value)}
value={password}/>
<span>mot de passe</span>
<div className="password error"></div>
</div>
<div className="password error"></div>
<br />
<input type="submit" value="connexion" id='connexion' />

@ -1,4 +1,5 @@
import React, { useState } from 'react';
import { NavLink, redirect} from "react-router-dom";
import axios from "axios";
import Connexion from "./Connexion";
@ -8,6 +9,7 @@ const Inscription = () => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [controlPassword, setControlPassword] = useState('');
const handleRegister = async (e) => {
e.preventDefault();
@ -52,69 +54,67 @@ const Inscription = () => {
.catch((err) => console.log(err));
}
};
/* const showText=()=>{
const timeoutID =setTimeout(()=>{document.getElementById("textSucces").style.visibility="visible"},3000);
clearTimeout(timeoutID);
};
*/
return (
<>
{formSubmit ? (
<div className='enregistrementReussi'>
<Connexion error={true} />
</div>
<Connexion error={true}/>
) : (
<div className="formulaire">
<form className="cadre" action='' onSubmit={handleRegister} >
<h1>Inscription</h1>
<div className="inputbox">
<span>pseudo</span>
<input type="text"
name="pseudo"
id="pseudo"
onChange={(e) => setPseudo(e.target.value)}
value={pseudo}/>
<span>pseudo</span>
<div className='pseudo error'></div>
</div>
<div className='pseudo error'></div>
<br />
<div className="inputbox">
<span>email</span>
<input type="text"
name="email"
id="email"
onChange={(e) => setEmail(e.target.value)}
value={email}/>
<span>email</span>
<div className='email error'></div>
</div>
<div className='email error'></div>
<br />
<div className="inputbox">
<span>mot de passe</span>
<input type="password"
name="password"
id="password"
onChange={(e) => setPassword(e.target.value)}
value={password}/>
<span>mot de passe</span>
<div className='password error'></div>
</div>
<div className='password error'></div>
<br />
<div className="inputbox">
<span>comfirmation mot de passe</span>
<input type="password"
name="password"
id="password-conf"
onChange={(e) => setControlPassword(e.target.value)}
value={controlPassword}/>
<span>comfirmation mot de passe</span>
<div className='password-confirm error'></div>
</div>
<div className='password-confirm error'></div>
<br />
<div className="chexkboxConditionGenerale">
<input type="checkbox"
name="terms"
id="terms"/>
<span>J'accepte les <a href="/" target="_blank" rel='noopener noreferrer'>conditions générales</a></span>
<div className="terms error"></div>
</div>
<div className="terms error"></div>
<br />
<input type="submit" value="inscription" id="inscription"/>

@ -1,33 +0,0 @@
#suivreAussi{
font-size: 8px;
text-align: center;
border: 2px solid;
border-radius: 30px;
width: 200px;
}
#listeCompteASuivre{
border-top: 2px solid;
}
.infoPersonne{
display: flex;
}
.name{
font-size: 12px;
}
.arobase{
color:gray;
}
.PhotoProfile{
margin: 10px 15px 0px 20px;
width: 40px;
height:40px;
border-radius: 20px;
border: 2px solid #555;
}

@ -1,36 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ma page de test</title>
<link rel="stylesheet" href="SuivreAussi.css" />
</head>
<body>
<div id="suivreAussi">
<h1>Suivre aussi</h1>
<div id="listeCompteASuivre">
<div class="infoPersonne">
<img class="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<div class="cadreName">
<h2 class="name">personne 1</h2>
<h3 class="arobase">@personne1</h3>
</div>
</div>
<div class="infoPersonne">
<img class="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<div class="cadreName">
<h2 class="name">personne 1</h2>
<h3 class="arobase">@personne1</h3>
</div>
</div>
<div class="infoPersonne">
<img class="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<div class="cadreName">
<h2 class="name">personne 1</h2>
<h3 class="arobase">@personne1</h3>
</div>
</div>
</div>
</div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 226 B

@ -1,165 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Titre du document</title>
<style>
#likeCommentaire{
background-color: white;
position:fixed;
margin-left:33%;
margin-right: 33%;
border: 2px solid #666;
border-radius:10px;
width: 33%;
}
#divButton{
display:flex;
justify-content: space-between;
}
#divButton > div{
width:50%;
}
#buttonLike,#buttonCommentaire {
margin-top:10px;
background-color: white;
border:none;
width:100%;
height:25px;
}
#buttonLike{
border-bottom:solid 5px black;
}
#like{
display: block;
}
#buttonCommentaire{
border-bottom: none;
}
#commentaire{
display: none;
}
/*like et commentaire*/
#like, #commentaire{
font-size: 8px;
text-align: center;
}
#listeCompteASuivre{
border-top: 2px solid;
}
.infoPersonne{
display: flex;
}
.name{
font-size: 12px;
}
.arobase{
color:gray;
}
.PhotoProfile{
margin: 10px 15px 0px 20px;
width: 40px;
height:40px;
border-radius: 20px;
border: 2px solid #555;
}
</style>
</head>
<body>
<div id="likeCommentaire">
<div id="divButton">
<div><button type="button" id="buttonLike" onclick="openLike()">like</button></div>
<div><button type="button" id="buttonCommentaire" onclick="openCommentaire()">commentaire</button></div>
</div>
<div id="like">
<div class="infoPersonne">
<img class="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<div class="cadreName">
<h2 class="name">personne 1</h2>
<h3 class="arobase">@personne1</h3>
</div>
</div>
<div class="infoPersonne">
<img class="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<div class="cadreName">
<h2 class="name">personne 1</h2>
<h3 class="arobase">@personne1</h3>
</div>
</div>
<div class="infoPersonne">
<img class="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<div class="cadreName">
<h2 class="name">personne 1</h2>
<h3 class="arobase">@personne1</h3>
</div>
</div>
</div>
<div id="commentaire">
<div class="infoPersonne">
<img class="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<div class="cadreName">
<h2 class="name">personne 1</h2>
<h3 class="arobase">@personne1</h3>
<h4>texte du commantaire</h4>
</div>
</div>
<div class="infoPersonne">
<img class="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<div class="cadreName">
<h2 class="name">personne 1</h2>
<h3 class="arobase">@personne1</h3>
<h4>texte du commantaire</h4>
</div>
</div>
<div class="infoPersonne">
<img class="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<div class="cadreName">
<h2 class="name">personne 1</h2>
<h3 class="arobase">@personne1</h3>
<h4>texte du commantaire</h4>
</div>
</div>
</div>
</div>
</body>
<script>
function openLike() {
document.getElementById("like").style.display = "block";
document.getElementById("buttonLike").style.borderBottom = "solid 5px black";
document.getElementById("commentaire").style.display = "none";
document.getElementById("buttonCommentaire").style.borderBottom = "none";
}
function openCommentaire() {
document.getElementById("like").style.display = "none";
document.getElementById("buttonLike").style.borderBottom = "none";
document.getElementById("commentaire").style.display = "block";
document.getElementById("buttonCommentaire").style.borderBottom = "solid 5px black";
}
</script>
</html>

@ -1,111 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Titre du document</title>
<style>
* {
box-sizing: border-box;
}
body {
font-family: Roboto, Helvetica, sans-serif;
}
.form-popup {
background-color: white;
display: none;
position:fixed;
margin-left:33%;
margin-right: 33%;
border: 2px solid #666;
border-radius:10px;
width: 33%;
}
/* Largeur complète pour les champs de saisie */
.form-container input[name="lien"],
.form-container textarea[name="description"],
.form-container label{
width: 80%;
margin: 10px 10% 50px 10%;
}
textarea{
resize: none;
height: 100px;
}
input[name="lien"],
textarea[name="description"]{
margin-left: 100px;
border: none;
background: #D9D9D9;
}
.input{
margin-top:20px;
}
#buttonForm{
margin-left:10%;
margin-right:10%;
margin-bottom:10px;
display:flex;
justify-content: space-between;
}
</style>
</head>
<body>
<h2>Forme Popup</h2>
<p>Cliquez sur le bouton "Ouvrir la forme" pour ouvrir la fdbjfndbfhbdbnfhdbfnbdhbfhbdhbfhdbfhdhbfhdbhfforme Popup.</p>
<div class="open-btn">
<button class="open-button" onclick="openForm()"><strong>Ouvrir la forme</strong></button>
</div>
<div>
<div class="form-popup" id="popupFormulaireCreationPoste">
<form action="/action_page.php" class="form-container">
<div class="input">
<label for="lien">Lien:</label>
<input type="text" name="lien" required />
</div>
<div class="input">
<label for="description">Description:</label>
<textarea name="description" row =250></textarea>
</div>
<div id="buttonForm">
<div>
<button type="button" class="btn cancel" onclick="closeForm()">retour</button>
</div>
<div>
<button type="submit" class="btn">Poster</button>
</div>
</div>
</form>
</div>
</div>
<script>
function openForm() {
document.getElementById("popupFormulaireCreationPoste").style.display = "block";
}
function closeForm() {
document.getElementById("popupFormulaireCreationPoste").style.display = "none";
}
</script>
</body>
</html>

@ -1,32 +0,0 @@
#PhotoProfile{
display: block;
margin-left: auto;
margin-right: auto;
width: 150px;
height:150px;
border-radius: 80px;
border: 2px solid #555;
}
#blocAbonnement{
display: flex;
justify-content: center;
}
#blocAbonnement div{
margin-left: 80px;
margin-right: 80px;
}
#blocName{
text-align: center;
}
.nombre{
color:black;
}
.texteNombre{
color:grey;
}

@ -1,28 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ma page de test</title>
<link rel="stylesheet" href="pagePerso.css" />
</head>
<body>
<div id="image">
<img id="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
</div>
<div id="blocName">
<h1>Lena 1er</h1>
<h2 class="subdo">@Lena1er</h2>
<div>
<div id="blocAbonnement">
<div>
<div class="nombre">10k</div>
<div class="texteNombre">Abonnement</div>
</div>
<div>
<div class="nombre">10k</div>
<div class="texteNombre">Abonnée</div>
</div>
</div>
</body>
</html>

@ -1,74 +0,0 @@
body{
background: green;
}
#cadrePoste{
background: white;
border-radius: 5px;
width: 40%;
margin-left: auto;
margin-right: auto;
}
/*haut du poste*/
/*
#cadreInfoPoste{
display: flex;
align-items:center;
}
#PhotoProfile{
margin: 10px 15px 0px 20px;
width: 40px;
height:40px;
border-radius: 20px;
border: 2px solid #555;
}
#NomProfile{
font-family: arial;
font-size: 18px;
}*/
#hautPoste{
display: flex;
align-items:center;
justify-content: space-between;
margin-right: 15px;
}
#cadreInfoPoste{
display: flex;
align-items:center;
}
#PhotoProfile{
margin: 10px 15px 0px 20px;
width: 40px;
height:40px;
border-radius: 20px;
border: 2px solid #555;
}
#NomProfile{
font-family: arial;
font-size: 18px;
}
/*bas poste*/
#basPoste{
display: flex;
align-items:center;
justify-content: space-between;
margin-left: 10px;
margin-right: 10px;
}
#like, #commentaire{
display: flex;
align-items:center;
}

@ -1,43 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ma page de test</title>
<link rel="stylesheet" href="poste.css" />
</head>
<body>
<!--<div id="cadrePoste">
<div id="cadreInfoPoste">
<img id="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<h6 id="NomProfile">Lena 1er</h6>
</div>
</div>-->
<div id="cadrePoste">
<div id="hautPoste">
<div id="cadreInfoPoste">
<img id="PhotoProfile" src="https://i.pinimg.com/originals/5c/a0/cf/5ca0cf624647dced23ec5329ed0cde6f.png"/>
<h6 id="NomProfile">Lena 1er</h6>
</div>
<div>6 jours</div>
</div>
<div id="contenuePoste">
/*utliser leakpreview*/
</div>
<div id="basPoste">
<div id="like">
<img src="coeurs.png">
<div>10k</div>
</div>
<div id="commentaire"> </>
<img src="commentaire.png">
<div>10k</div>
</div>
</div>
</div>
</body>
</html>

@ -0,0 +1,35 @@
import React, {useEffect,useState} from 'react';
import {useDispatch, useSelector} from "react-redux";
import {getPosts} from "../actions/post.actions";
import {getUserTemp} from "../actions/user.actions";
import {useParams} from "react-router-dom";
import {isEmpty} from "./Utils";
import FollowHandler from "./UserProfil/FollowHandler";
const MiniProfil = ({uid} ) => {
const [userData, setUserData] = useState(null);
useEffect(() => {
async function fetchData() {
const response = await fetch(`${process.env.REACT_APP_API_URL}api/user/${uid}`);
const data = await response.json();
setUserData(data);
}
fetchData();
}, [uid]);
if (!userData) {
return <p>Loading...</p>;
}
return (
<div className="ListReco">
<div className="UtiReco">
<img className="image" src={userData.picture}/>
<a href={`/Profil/${uid}`}>{userData.pseudo}</a>
</div>
</div>
);
};
export default MiniProfil;

@ -23,7 +23,7 @@ const Navbar = () => {
data.append('postedId', userData._id);
data.append('message', description);
data.append('lien', lien);
console.log(data);
//console.log("test",data);
putData(data);
console.log(data);
cancelPost();
@ -75,10 +75,9 @@ const Navbar = () => {
})
.then(() => removeCookie('jwt'))
.catch((err) => console.log(err));
window.location = "/HomeNavigation";
window.location = "/";
}
return (
<div>
{uid ? (
@ -110,16 +109,22 @@ const Navbar = () => {
</NavLink>
</li>
<li className="navbar-item">
<NavLink to="/Profil" className="navbar-link">
<NavLink to={`/Profil/${uid}`} className="navbar-link">
<i className="fas fa-user navbar-icon"></i>
<span className="navbar-title">Me</span>
</NavLink>
</li>
<li className="navbar-item">
<a onClick={() => setDisplayAdd(true)} className="navbar-link">
<NavLink to="/SearchBar" className="navbar-link">
<i className="fas fa-search navbar-icon"></i>
<span className="navbar-title">Recherche</span>
</NavLink>
</li>
<li className="navbar-item">
<NavLink to="/Configuration" className="navbar-link">
<i className="fas fa-cog navbar-icon"></i>
<span className="navbar-title">Paramètre</span>
</a>
</NavLink>
</li>
<li className="navbar-item">
<a onClick={logout} className="navbar-link">

@ -0,0 +1,31 @@
import React, {useEffect,useState} from 'react';
import {useDispatch, useSelector} from "react-redux";
import {getPosts} from "../actions/post.actions";
import {getUserTemp} from "../actions/user.actions";
import MiniProfil from "./MiniProfil";
const Notif = ({notification} ) => {
console.log('notification',notification)
const MessageNotif = (notification) =>{
if(notification.typeNotif == 'like') {
return "a like votre post";
}
else if(notification.typeNotif == 'commente') {
return "a commenter votre post";
}
return 'vous follow'
}
return (
<div className='conteneur_notif' key={notification._id}>
<MiniProfil uid={notification.id_user}></MiniProfil>
<div className={'contenue_notif'}>
{ MessageNotif(notification) }
</div>
</div>
);
};
export default Notif;

@ -0,0 +1,69 @@
import React, { useContext, useEffect, useState } from 'react';
import { useDispatch } from 'react-redux';
import { deleteComment, editComment } from '../../actions/post.actions';
import { UidContext } from '../AppContext';
const ActionComment = ( { commentaire , postId}) => {
const [createur, setCreateur] = useState(false);
const [edit, setEdit] = useState(false);
const [message,setMessage] = useState('');
const uid = useContext(UidContext);
const dispatch = useDispatch();
const handleEdit = (e) => {
e.preventDefault();
if(message){
dispatch(editComment(postId, commentaire._id, message));
setMessage('');
setEdit(false);
}
};
const handleDelete = () => {
dispatch(deleteComment(postId, commentaire._id));
};
useEffect(() => {
const verifCreateur = () => {
if(uid === commentaire.commentId){
setCreateur(true);
}
}
console.log(commentaire);
verifCreateur();
console.log(createur);
}, [uid, commentaire.commenterId]);
return (
<div className="edit-comment">
{createur && edit === false && (
<span onClick={() => setEdit(!edit)}>
<i className='fas fa-edit'></i>
</span>
)}
{createur && edit && (
<form action="" onSubmit={handleEdit}
className="edit-comment-form">
<label htmlFor='text' onClick={() => setEdit(!edit)}>Modifier le commentaire</label>
<input type="text" name="text" onChange={(e) => setMessage(e.target.value)} defaultValue={commentaire.text}/>
<br/>
<div className="btn">
<span onClick={() => {
if(window.confirm("Etes-vous sur de supprimer ce commentaire ?")){
handleDelete();
}
}}>
<i className="fas fa-trash-alt"></i>
</span>
</div>
<input type="submit" value="Modifier"/>
</form>
)}
</div>
);
};
export default ActionComment;

@ -0,0 +1,88 @@
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addComment, getPosts } from '../../actions/post.actions';
import FollowHandler from '../UserProfil/FollowHandler';
import { isEmpty, timestampParser } from '../Utils';
import ActionComment from './ActionComment';
const Comment = ({ post }) => {
const [message, setMessage] = useState("");
const usersData = useSelector((state) => state.users.users);
const userData = useSelector((state) => state.user.user);
const dispatch = useDispatch();
const handleComment = (e) => {
e.preventDefault();
if (message) {
dispatch(addComment(post._id, userData._id, message, userData.pseudo))
.then(() => dispatch(getPosts()))
.then(() => setMessage(''));
}
};
return (
<div className="comments-container">
{post.comments.map((comment) => {
return (
<div
className={
comment.commenterId === userData._id
? "comment-container client"
: "comment-container"
}
key={comment._id}
>
<div className="left-part">
<img
src={
!isEmpty(usersData[0]) &&
usersData
.map((user) => {
if (user._id === comment.commenterId) return user.picture;
else return null;
})
.join("")
}
alt="commenter-pic"
/>
</div>
<div className="right-part">
<div className="comment-header">
<div className="pseudo">
<h3>{comment.commenterPseudo}</h3>
{comment.commenterId !== userData._id && (
<FollowHandler
idToFollow={comment.commenterId}
type={"suggest"}
/>
)}
</div>
<span>{timestampParser(comment.timestamp)}</span>
</div>
<p>{comment.text}</p>
<ActionComment commentaire={comment} postId={post._id} />
</div>
</div>
);
})}
{userData._id && (
<form action="" onSubmit={handleComment} className="comment-form">
<input
type="text"
name="text"
onChange={(e) => setMessage(e.target.value)}
value={message}
placeholder="Laisser un commentaire"
/>
<br />
<input type="submit" value="Envoyer" />
</form>
)}
</div>
);
};
export default Comment;

@ -0,0 +1,32 @@
import { current } from '@reduxjs/toolkit';
import React, { useEffect, useState, useContext } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from '../../../actions/post.actions';
import { isEmpty } from "../../Utils";
import Post from '../PostNouvelleAffichage';
import { UidContext } from '../../AppContext';
const DiplayPostDossier = () => {
const postsData = useSelector((state) => state.post.post);
const uid = useContext(UidContext);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getPosts());
},[dispatch])
return (
<div>
<ul>
{!isEmpty(postsData[0]) &&
postsData.map((post) => {
if(post.postedId === uid){
return <Post post={post} key={post._id}/>
}
})}
</ul>
</div>
);
};
export default DiplayPostDossier;

@ -0,0 +1,33 @@
import { current } from '@reduxjs/toolkit';
import React, { useEffect, useState, useContext } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from '../../../actions/post.actions';
import { isEmpty } from "../../Utils";
import Post from '../PostNouvelleAffichage';
import { UidContext } from '../../AppContext';
const DisplayPostLikeProfil = () => {
const postsData = useSelector((state) => state.post.post);
const uid = useContext(UidContext);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getPosts());
},[dispatch])
return (
<div>
<ul>
{!isEmpty(postsData[0]) &&
postsData.filter(post => post.likers.includes(uid))
.map((post) => {
return <Post post={post} key={post._id}/>
})
}
</ul>
</div>
);
};
export default DisplayPostLikeProfil;

@ -0,0 +1,31 @@
import { current } from '@reduxjs/toolkit';
import React, { useEffect, useState, useContext } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from '../../../actions/post.actions';
import { isEmpty } from "../../Utils";
import Post from '../PostNouvelleAffichage';
import { UidContext } from '../../AppContext';
const NouveauDisplayPosts = () => {
const postsData = useSelector((state) => state.post.post);
const uid = useContext(UidContext);
const dispatch = useDispatch();
useEffect(() => {
dispatch(getPosts());
},[dispatch])
return (
<div>
<ul>
{!isEmpty(postsData[0]) &&
postsData.map((post) => {
if(post.postedId === uid){
return <Post post={post} key={post._id}/>
}
})}
</ul>
</div>
);
};
export default NouveauDisplayPosts;

@ -1,22 +1,38 @@
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from '../../actions/post.actions';
import NewPoste from '../NewPoste';
import { getPosts, getPostsDisc } from '../../actions/post.actions';
import { isEmpty } from "../Utils";
import Post from './Post';
const DisplayPosts = () => {
const DisplayPosts = ( {type} ) => {
const [loadPost, setLoadPost] = useState(true);
const [count , setCount] = useState(5);
const dispatch = useDispatch();
const postsData = useSelector((state) => state.post.post);
const loadMore = () => {
if (window.innerHeight + document.documentElement.scrollTop + 1 > document.scrollingElement.scrollHeight){
setLoadPost(true);
}
}
useEffect(() => {
while(postsData== null){
}
if (loadPost) {
dispatch(getPosts());
if(type === "discover"){
dispatch(getPostsDisc(count));
}
else{
dispatch(getPosts(count));
}
setLoadPost(false);
setCount(count + 5);
}
}, [loadPost,dispatch])
window.addEventListener('scroll', loadMore);
return () => window.removeEventListener('scroll',loadMore);
}, [loadPost,dispatch,count])
return (
<div>

@ -0,0 +1,45 @@
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from '../../actions/post.actions';
import { isEmpty } from "../Utils";
import Post from './PostNouvelleAffichage';
const NouveauDisplayPosts = () => {
const [loadPost, setLoadPost] = useState(true);
const [count , setCount] = useState(5);
const dispatch = useDispatch();
const postsData = useSelector((state) => state.post.post);
const loadMore = () => {
if (window.innerHeight + document.documentElement.scrollTop + 1 > document.scrollingElement.scrollHeight){
setLoadPost(true);
}
}
useEffect(() => {
if (loadPost) {
dispatch(getPosts(count));
setLoadPost(false);
setCount(count + 5);
}
window.addEventListener('scroll', loadMore);
return () => window.removeEventListener('scroll',loadMore);
}, [loadPost,dispatch,count])
if (loadPost || (postsData === null || isEmpty(postsData)) ) {
return <p>Loading...</p>;
}
return (
<div>
<ul>
{ postsData === null && !isEmpty(postsData[0]) && postsData.map((post) => {
return <Post post={post} key={post._id}/>
})}
</ul>
</div>
);
};
export default NouveauDisplayPosts;

@ -1,16 +1,20 @@
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import React, { Component, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import FollowHandler from '../UserProfil/FollowHandler';
import { dateParser, isEmpty } from '../Utils';
import ButtonLike from './ButtonLike';
import Comment from './Comment';
import Commentaire from '../../assets/img/commentaire.png';
import MiniProfil from "../MiniProfil";
const LinkPreview = ({ link }) => {
const [preview, setPreview] = useState({ image: '', title: '', description: '' });
useEffect(() => {
const key = '9f24d981b6f0ddfce993ce4a20d58867';
//const key = '9f24d981b6f0ddfce993ce4a20d58867';
const key = '2865b6b9d9571dc00bf940fad5728248';
const fullLink = `http://api.linkpreview.net/?key=${key}&q=${link}`;
axios
@ -19,17 +23,22 @@ const LinkPreview = ({ link }) => {
.catch((err) => console.error(err));
}, [link]);
return (
<div>
<a href={link}>
<img id="imageLien" src={preview.image} alt={preview.title} />
</a>
<a id="url" href={link}>
{link}
</a>
if(preview.image === "") {
return (<div className='alignementLien'><a className="LienPostHome" href={link}>{link}</a></div>);
}
else {
return (
<>
<div className='alignementLien'>
<a href={link}>
<img id="imageLien" className="LienPostHome" src={preview.image} alt={preview.title}/>
</a>
</div>
<p>{preview.description}</p>
</div>
);
</>
);
}
};
//e.preventDefaul(); pour ne pas recharcher la page
@ -37,9 +46,13 @@ const Post = ( { post } ) => {
const [isLoading, setIsLoading] = useState(true);
const usersData = useSelector((state) => state.users.users);
const userData = useSelector((state) => state.user.user);
const [updated,setUpdate] = useState(false);
const [message, setMessage] = useState(null);
const [comments, setComments] = useState(false);
useEffect(() => {
!isEmpty(usersData[0]) && setIsLoading(false)
!isEmpty(usersData[0]) && !isEmpty(userData) && setIsLoading(false)
})
return (
@ -51,34 +64,17 @@ const Post = ( { post } ) => {
<div id="postContenu">
<div id="hautPoste">
<div id="cadreInfoPoste">
<img id="PhotoProfile" alt="" src={
!isEmpty(usersData[0]) &&
usersData.map((user) => {
if (user._id === post.postedId) return user.picture;
else return null;
}).join('')
}/>
<h6 id="NomProfile">
{
!isEmpty(usersData[0]) &&
usersData.map((user) => {
if(user._id === post.postedId) return user.pseudo;
else return null;
}).join('')
}
</h6>
{/* {post.postedId !== userData._id &&
(<FollowHandler idToFollow={post.postedId} type={'suggest'}/>)} */}
<MiniProfil uid={post.postedId}/>
{post.postedId !== userData._id && (<FollowHandler idToFollow={post.postedId} type={'suggest'}/>)}
</div>
<div>{dateParser(post.createdAt)}</div>
</div>
<div id="contenuePoste">
<LinkPreview link="https://www.bbc.com/news/uk-politics-63335671" />
<LinkPreview link={post.lien}/>
<p>{post.message}</p>
</div>
<div id="basPoste">
<div id="like">
<ButtonLike post={post}/>
@ -86,10 +82,11 @@ const Post = ( { post } ) => {
<div>{post.likers.length}</div>
</div>
<div id="commentaire">
<img src="commentaire.png"/>
<img src={Commentaire} onClick={() => setComments(!comments)}/>
<div>{post.comments.length}</div>
</div>
</div>
{comments && <Comment post={post} />}
</div>
</div>) }
</li>

@ -0,0 +1,92 @@
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import FollowHandler from '../UserProfil/FollowHandler';
import { dateParser, isEmpty } from '../Utils';
import ButtonLike from './ButtonLike';
import Comment from './Comment';
const LinkPreview = ({ link }) => {
const [preview, setPreview] = useState({ image: '', title: '' });
useEffect(() => {
//const key = '9f24d981b6f0ddfce993ce4a20d58867';
const key = '2865b6b9d9571dc00bf940fad5728248';
const fullLink = `http://api.linkpreview.net/?key=${key}&q=${link}`;
axios
.get(fullLink)
.then((res) => setPreview(res.data))
.catch((err) => console.error(err));
}, [link]);
if(preview.image === "") {
return (<div className='PreviewPostNouvelleAffichage'><a href={link}>{link}</a></div>);
}
else {
return (
<div>
<a href={link}>
<img id="imageLien" className='PreviewPostNouvelleAffichage' src={preview.image} alt={preview.title}/>
</a>
</div>
);
}
};
//e.preventDefaul(); pour ne pas recharcher la page
const PostNouvelleAffichage = ( { post } ) => {
const [isLoading, setIsLoading] = useState(true);
const usersData = useSelector((state) => state.users.users);
const [updated,setUpdate] = useState(false);
const [message, setMessage] = useState(null);
const [comments, setComments] = useState(false);
useEffect(() => {
!isEmpty(usersData[0]) && setIsLoading(false)
})
if(!isLoading){
return <p></p>;
}
return (
<li className='PostesProfilConteneur' key={post._id}>
{isLoading ? (
<i className='fas fa-spinner fa-spin'></i>
):(
<>
<div className="unPosteNouvelleAffichage">
<div className="dateDePublicationDuPost">
<div>{dateParser(post.createdAt)}</div>
</div>
<div className="LienDunPosteNouvelleAffichage">
<LinkPreview link={post.lien}/>
<p>{post.message}</p>
</div>
<div className='informationDunPosteNouvelleAffichage'>
<div id="like">
<ButtonLike post={post}/>
{/* <img src="coeurs.png"/> */}
<div>{post.likers.length}</div>
</div>
<div id="commentaire">
<img src="commentaire.png" onClick={() => setComments(!comments)}/>
<div >{post.comments.length}</div>
</div>
</div>
</div>
{comments && <Comment className="CommentaireProfil" post={post} />}
</>
) }
</li>
);
};
//ce qui écrit dans le input est récuperé par le state
export default PostNouvelleAffichage;

@ -5,19 +5,21 @@ import Home from '../../pages/Home.js';
import Trends from '../../pages/Trends.js';
import Discover from '../../pages/Discover.js';
import Profil from '../../pages/Profil.js';
import Configuration from '../../pages/Configuration';
import Configuration from '../../pages/Configuration.js';
import SearchBar from '../../pages/SearchBar.js';
const index = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<HomeNavigation/>} />
<Route path="/h" element={<Home/>} />
<Route path="/trends" element={<Trends/>} />
<Route path="/discover" element={<Discover/>} />
<Route path="*" element={<HomeNavigation/>} />
<Route path="/profil" element={<Profil />} />
<Route path="/configuration" element={<Configuration/>}/>
<Route path="/Home" element={<Home/>} />
<Route path="/Trends" element={<Trends/>} />
<Route path="/Discover" element={<Discover/>} />
<Route path="/SearchBar" element={<SearchBar/>} />
{/* <Route path="*" element={<HomeNavigation/>} /> */}
<Route path="/Profil/:uid" element={<Profil/>} />
<Route path="/Configuration" element={<Configuration/>}/>
</Routes>
</BrowserRouter>
);

@ -10,24 +10,26 @@ const FollowHandler = ( { idToFollow , type } ) => {
const [isFollowed, setIsFollowed] = useState(false);
const dispatch = useDispatch();
const handleFollow = () => {
const handleFollow = (e) => {
axios.patch(`${process.env.REACT_APP_API_URL}api/user/follow/` + userData._id, {params: {idToFollow: idToFollow}} )
axios.patch(`${process.env.REACT_APP_API_URL}api/user/follow/` + userData._id, {idToFollow: idToFollow})
.then((res) => {
//dispatch(setUserToFollowData({payload: {idToFollow}}));
})
.catch((err) => console.log(err));
setIsFollowed(false);
setIsFollowed(true);
e.preventDefault();
};
const handleUnFollow = () => {
const handleUnFollow = (e) => {
axios.patch(`${process.env.REACT_APP_API_URL}api/user/unfollow/` + userData._id, {params: {idToFollow: idToFollow}} )
axios.patch(`${process.env.REACT_APP_API_URL}api/user/unfollow/` + userData._id, {idToUnFollow: idToFollow})
.then((res) => {
// dispatch(setUserToUnFollowData({payload: {idToFollow}}));
})
.catch((err) => console.log(err));
setIsFollowed(false);
e.preventDefault();
};

@ -0,0 +1,18 @@
import DiplayPostDossier from "../../Post/DisplayPost/DiplayPostDossier";
const DossiersPersonnels=()=>{
return(
<div className='dossierPersonnel'>
<DiplayPostDossier/>
</div>
)
}
export default DossiersPersonnels;

@ -0,0 +1,20 @@
import DisplayPostLikeProfil from "../../Post/DisplayPost/DisplayPostLikeProfil";
const PostLikes=()=>{
return(
<div className='postPersonnel'>
<DisplayPostLikeProfil/>
</div>
)
}
export default PostLikes;

@ -0,0 +1,20 @@
import NouveauDisplayPosts from "../../Post/DisplayPost/NouveauDisplayPosts";
const PostPersonnels=()=>{
return(
<div className='postPersonnel'>
<NouveauDisplayPosts/>
</div>
)
}
export default PostPersonnels;

@ -0,0 +1,98 @@
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { isEmpty } from '../Utils';
import FollowHandler from './FollowHandler';
const SuggestFriends = () => {
const userData = useSelector((state) => state.user.user);
const usersData = useSelector((state) => state.users.users);
const [chargement,setChargement] = useState(true);
const [change, setChange] = useState(true);
const [friends, setFriends] = useState([]);
useEffect(() => {
const stateFriend = () => {
let array = [];
usersData.map((user) => {
if(user._id !== userData._id && user.followers.includes(userData._id)){
return array.push(user._id);
}
})
//mettre dans un ordre aléatoire
array.sort(() => 0.5 - Math.random());
if(window.innerHeight > 780){
array.length = 5;
}
if(window.innerHeight > 720){
array.length = 4;
}
if(window.innerHeight > 660){
array.length = 3;
}
if(window.innerHeight > 600){
array.length = 2;
}
if(window.innerHeight > 540){
array.length = 1;
}else {
array.length = 0;
}
setFriends(array);
}
const stateTopFollowers = () => {
let array = [];
let obj = JSON.parse(JSON.stringify(usersData));
obj.sort((a, b) => b.followers.length - a.followers.length);
obj.map((user) => {
if(user._id !== userData._id && !user.followers.includes(userData._id)){
return array.push(user._id);
}
})
console.log(array);
array = array.splice(0, 5);
setFriends(array);
}
if(change && !isEmpty(usersData[0]) && userData!=null){
if(userData.followers.length === 0){
stateTopFollowers();
}else{
stateFriend();
}
setChargement(false);
setChange(false);
}
}, [userData, usersData, change])
return (
<div className="recoDiv">
<div className="reco">
<span>Vous pourriez suivre</span>
<hr/>
{chargement ? (
<i className='fas fa-spinner fa-pulse'></i>
) : (
<div className="ListReco" >
{friends && friends.map((user) => {
for(let i = 0; i < usersData.length; i++){
if(user === usersData[i]._id){
return (
<div className="UtiReco" key={user}>
<img src={usersData[i].picture} alt="img"/>
<p>{usersData[i].pseudo}</p>
<FollowHandler idToFollow={usersData[i]._id} type={"card"}/>
</div>
);
}
}
})}
</div>
)}
</div>
</div>
);
};
export default SuggestFriends;

@ -22,6 +22,9 @@ export const dateParser = (num) => {
return date.toString();
};
export const timestampParser = (num) => {
let options = {
hour: "2-digit",

@ -4,11 +4,12 @@ import ConfigurationDuProfil from '../components/Configurations/ConfigurationDuP
import ConfigurationDuCompte from '../components/Configurations/ConfigurationDuCompte.js';
import PolitiqueDeConfidentialite from '../components/Configurations/PolitiqueDeConfidentialite';
import Navbar from '../components/Navbar';
function Configuration(){
const Configuration = () => {
const [ConfigurationCompte, setConfigurationDuCompte] = useState(false);
const [ConfigurationProfil, setConfigurationDuProfil] = useState(true);
const [PolitiqueConfidentialite, setPolitiqueDeConfidentialite] =useState(false)
const [PolitiqueConfidentialite, setPolitiqueDeConfidentialite] =useState(false);
const handleModals = (e) => {
if (e.target.id === "ConfigurationDuProfil") {
@ -29,22 +30,24 @@ function Configuration(){
return(
<>
<Navbar />
<div className='configuration'>
<div className='boutonDeConfigurations'>
<button onClick={handleModals} id="ConfigurationDuProfil" className={ConfigurationProfil} >
<a onClick={handleModals} id="ConfigurationDuProfil" >
Configuration du profil
</button>
<button onClick={handleModals} id="ConfigurationDuCompte" className={ConfigurationCompte}>
</a>
<a onClick={handleModals} id="ConfigurationDuCompte" >
Configuration du compte
</button>
<button onClick={handleModals} id="PolitiqueDeConfidentialite" className={PolitiqueConfidentialite}>
</a>
<a onClick={handleModals} id="PolitiqueDeConfidentialite" >
Politique de confidentialite
</button>
</a>
</div>
{ConfigurationProfil &&<ConfigurationDuProfil/>}
{ConfigurationCompte &&<ConfigurationDuCompte/>}
{PolitiqueConfidentialite &&<PolitiqueDeConfidentialite/>}
</div>
</>
);
}

@ -9,7 +9,7 @@ const Discover = () => {
<Navbar />
<main >
<div className='postInMain'>
<DisplayPosts/>
<DisplayPosts type={"discover"}/>
</div>
<div className="RightBar">
<AjoutLien/>

@ -1,18 +1,22 @@
import React from 'react';
import React, { useContext } from 'react';
import AjoutLien from '../components/AjoutLien';
import DisplayPosts from '../components/Post/DisplayPosts';
import Navbar from '../components/Navbar';
import SuggestFriends from '../components/UserProfil/SuggestFriends';
import { UidContext } from '../components/AppContext';
const Home = () => {
const uid = useContext(UidContext);
return (
<>
<Navbar />
<main >
<div className='postInMain'>
<DisplayPosts/>
<DisplayPosts type={"home"}/>
</div>
<div className="RightBar">
<AjoutLien/>
{uid && <SuggestFriends />}
</div>
</main>
</>

@ -3,11 +3,6 @@ import { UidContext } from '../components/AppContext';
import Log from '../components/Log'
import Home from './Home';
import { NavLink } from 'react-router-dom';
import NewPoste from "../components/NewPoste";
import AjoutLien from "../components/AjoutLien";
//<Link to="/discover"/>
const HomeNavigation = () => {
const uid = useContext(UidContext);

@ -1,43 +1,81 @@
import {React, useState} from 'react';
import React,{useEffect, useState} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom'
import Navbar from '../components/Navbar';
import { dateParser } from '../components/Utils';
import {dateParser, isEmpty} from '../components/Utils';
import FollowHandler from '../components/UserProfil/FollowHandler';
import PostPersonnels from '../components/UserProfil/NavigationProfil/PostsPersonnels';
import DossierPersonnels from '../components/UserProfil/NavigationProfil/DossiersPersonnels';
import PostsLikes from '../components/UserProfil/NavigationProfil/PostsLikes';
import MiniProfil from "../components/MiniProfil";
const Profil = () => {
const userData = useSelector((state) => state.user.user);
const usersData = useSelector((state) => state.users.users);
const dispatch = useDispatch();
const { uid } = useParams();
const [userData, setUserData] = useState(null);
const [followingPopup, setFollowingPopup] = useState(false);
const [followerPopup, setFollowerPopup] = useState(false);
const [dossierPersonnels,setdossierPersonnels ] = useState(false);
const [postPersonnels,setpostPersonnels ] = useState(true);
const [postLikes,setpostLikes ] = useState(false)
useEffect(() => {
async function fetchData() {
const response = await fetch(`${process.env.REACT_APP_API_URL}api/user/${uid}`);
const data = await response.json();
setUserData(data);
}
fetchData();
}, [uid]);
const handleModals = (e) => {
if (e.target.id === "DossierPersonnels") {
setdossierPersonnels(true);
setpostPersonnels(false);
setpostLikes(false);
} else if (e.target.id === "PostsPersonnels") {
setdossierPersonnels(false);
setpostPersonnels(true);
setpostLikes(false);
} else if (e.target.id ==="PostsLikes"){
setdossierPersonnels(false);
setpostPersonnels(false);
setpostLikes(true);
}
};
if (!userData) {
return <p>Loading...</p>;
}
return (
<>
<Navbar />
<main>
{/* <main>
<div id="bandeauProfil">
<h1 className='affichage-date'>Compte créé le : {dateParser(userData.createdAt)}</h1>
<h1 classNameName='affichage-date'>Compte créé le : {dateParser(userData.createdAt)}</h1>
<div id="image">
<img id="PhotoProfile" alt="Profil" src={userData.picture}/>
</div>
<div id="blocName">
<h1>{userData.pseudo}</h1>
<h2 className="subdo">@{userData.pseudo}</h2>
<h2 classNameName="subdo">@{userData.pseudo}</h2>
<div>
<div id="blocAbonnement">
<div onClick={() => setFollowingPopup(true)} className="bloc-aboonnements-abonner">
<div className="nombre">{userData.following.length}</div>
<div className="texteNombre">Abonnement</div>
<div onClick={() => setFollowingPopup(true)} classNameName="bloc-aboonnements-abonner">
<div classNameName="nombre">{userData.following.length}</div>
<div classNameName="texteNombre">Abonnement</div>
</div>
<div onClick={() => setFollowerPopup(true)} className="bloc-aboonnements-abonner">
<div className="nombre">{userData.followers.length}</div>
<div className="texteNombre">Abonnée</div>
<div onClick={() => setFollowerPopup(true)} classNameName="bloc-aboonnements-abonner">
<div classNameName="nombre">{userData.followers.length}</div>
<div classNameName="texteNombre">Abonnée</div>
</div>
{followingPopup && (
<div className="popup-profil-container">
<div className="modal">
<div classNameName="popup-profil-container">
<div classNameName="modal">
<h3>Abonnements</h3>
<span className="cross" onClick={() => setFollowingPopup(false)}>
<span classNameName="cross" onClick={() => setFollowingPopup(false)}>
&#10005;
</span>
<ul>
@ -48,7 +86,7 @@ const Profil = () => {
<li key={user._id}>
<img src={user.picture} alt="user-pic" />
<h4>{user.pseudo}</h4>
<div className="follow-handler">
<div classNameName="follow-handler">
<FollowHandler idToFollow={user._id} type={'card'}/>
</div>
</li>
@ -62,10 +100,10 @@ const Profil = () => {
</div>
)}
{followerPopup && (
<div className="popup-profil-container">
<div className="modal">
<div classNameName="popup-profil-container">
<div classNameName="modal">
<h3>Abonnés</h3>
<span className="cross" onClick={() => setFollowerPopup(false)}>
<span classNameName="cross" onClick={() => setFollowerPopup(false)}>
&#10005;
</span>
<ul>
@ -76,7 +114,7 @@ const Profil = () => {
<li key={user._id}>
<img src={user.picture} alt="user-pic" />
<h4>{user.pseudo}</h4>
<div className="follow-handler">
<div classNameName="follow-handler">
<FollowHandler idToFollow={user._id} type={'card'} />
</div>
</li>
@ -94,6 +132,141 @@ const Profil = () => {
</div>
</div>
</main> */}
<main>
<div>
<div>
<div className="imageProfil">
<img className="image" src={userData.picture}/>
</div>
<div className="divPseudo">
<h3 className="pseudo">{userData.pseudo}</h3>
{/* <h3>suuu</h3> */}
</div>
<div className="divSuivreFollowing">
<a href="#" className="button" id="button">Suivre +</a>
</div>
<div className="divSuivreFollowing">
<div className="nbFollow" onClick={() => setFollowingPopup(true)}>
<h4>{userData.following.length}</h4>
<h4 className="txtFollower">Abonnements</h4>
</div>
<div className="nbFollow" onClick={() => setFollowerPopup(true)}>
<h4>{userData.followers.length}</h4>
<h4 className="txtFollower">Abonnés</h4>
</div>
</div>
{followingPopup && (
<div className="popup-profil-container">
<div className="modal">
<h3>Abonnements</h3>
<span className="cross" onClick={() => setFollowingPopup(false)}>
&#10005;
</span>
<ul>
{
userData.following.map((follower, i) => {
return (
<li key={i}>
<MiniProfil uid={follower}/>
<div classNameName="follow-handler">
<FollowHandler idToFollow={uid} type={'card'}/>
</div>
</li>
)
})
}
</ul>
</div>
</div>
)}
{followerPopup && (
<div classNameName="popup-profil-container">
<div classNameName="modal">
<h3>Abonnés</h3>
<span classNameName="cross" onClick={() => setFollowerPopup(false)}>
&#10005;
</span>
<ul>
{
userData.followers.map((follower, i) => {
return (
<li key={i}>
<MiniProfil uid={follower}/>
<div classNameName="follow-handler">
<FollowHandler idToFollow={uid} type={'card'}/>
</div>
</li>
)
})
}
</ul>
</div>
</div>
)}
</div>
<div className="basDePage">
<div className="divMenu">
<div>
<nav role="navigation" className="navProfil">
<ul className="navItemsProfil">
<li className="navItemProfil">
<a className="navLinkProfil" id='DossierPersonnels' onClick={handleModals}>Dossier Personnel</a>
</li>
<li className="navItemProfil">
<a className="navLinkProfil" id='PostsPersonnels' onClick={handleModals}>Posts</a>
</li>
<li className="navItemProfil">
<a className="navLinkProfil" id='PostsLikes' onClick={handleModals}>Posts likés</a>
</li>
</ul>
</nav>
</div>
<div className="menuContent">
<div className="listContent">
{dossierPersonnels &&<DossierPersonnels/>}
{postPersonnels &&<PostPersonnels/>}
{postLikes &&<PostsLikes/>}
</div>
</div>
</div>
<div className="recoDiv">
<div className="reco">
<span>Vous pourriez suivre</span>
<hr/>
<div className="ListReco">
<div className="UtiReco">
<img className="image" src="https://ionicframework.com/docs/img/demos/avatar.svg"/>
<span>UtiT</span>
<a href="#" className="buttonReco" id="button">Suivre</a>
</div>
<div className="UtiReco">
<img className="image" src="https://ionicframework.com/docs/img/demos/avatar.svg"/>
<span>UtiT</span>
<a href="#" className="buttonReco" id="button">Suivre</a>
</div>
<div className="UtiReco">
<img className="image" src="https://ionicframework.com/docs/img/demos/avatar.svg"/>
<span>UtiT</span>
<a href="#" className="buttonReco" id="button">Suivre</a>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</>
)

@ -0,0 +1,83 @@
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import Navbar from '../components/Navbar';
const SearchBar = () => {
const [searchValue, setSearchValue] = useState("");
const [searchUsers, setSearchUsers] = useState(true);
const [searchPosts, setSearchPosts] = useState(false);
const [searchResults, setSearchResults] = useState([]);
const postsData = useSelector((state) => state.post.post);
const usersData = useSelector((state) => state.users.users);
function handleSearch() {
const input = searchValue.toLowerCase();
console.log("Recherche pour : " + input);
const filteredResultsUsers = usersData.filter(function(item) {
return item.pseudo.toLowerCase().indexOf(input) !== -1;
});
const filteredResultsPosts = postsData.filter(function(item) {
return item.message.toLowerCase().indexOf(input) !== -1;
});
if(searchUsers)
setSearchResults(filteredResultsUsers);
if(searchPosts)
setSearchResults(filteredResultsPosts);
console.log(searchResults);
}
const handleModals = (e) => {
if (e.target.id === "Users") {
setSearchUsers(true);
setSearchPosts(false);
} else {
setSearchPosts(true);
setSearchUsers(false);
}
};
return (
<div>
<Navbar />
<main>
<form>
<input type="text" value={searchValue} onChange={(e) => setSearchValue(e.target.value)} placeholder="Rechercher..." />
<button type="button" onClick={handleSearch}>Rechercher</button>
</form>
<div class="divMenu">
<nav role="navigation" class="navProfil">
<ul class="navItemsProfil">
<li class="navItemProfil">
<a class="navLinkProfil" onClick={handleModals} id="Users" >Utilisateur</a>
</li>
<li class="navItemProfil">
<a class="navLinkProfil" onClick={handleModals} id="Posts" >Postes</a>
</li>
</ul>
</nav>
</div>
{ searchUsers &&
<ul>
{searchResults.map((result) => (
<li key={result.pseudo}>{result.pseudo}</li>
))}
</ul>
}
{ searchPosts &&
<ul>
{searchResults.map((result) => (
<li key={result.message}>{result.message}</li>
))}
</ul>
}
</main>
</div>
);
};
export default SearchBar;

@ -1,9 +1,28 @@
import React from 'react';
import React, {useState} from 'react';
import Navbar from '../components/Navbar';
import Notif from '../components/Notif';
import {useSelector} from "react-redux";
const Trends = () => {
const [setLoadNotif] = useState(true);
const userData = useSelector((state) => state.user.user);
return (
<Navbar />
<div id={'listeNotif'}>
<Navbar />
<h1>Notification</h1>
{
userData.notif != null && userData.notif.map((notif) => {
return (
<li>
<Notif key={notif._id} notification={notif}/>
</li>
);
})
}
</div>
);
};

@ -22,6 +22,7 @@ export const userSlice = createSlice({
(id) => id !== action.payload.idToUnfollow
),};
},
},
});

@ -5,8 +5,11 @@ $color-2: #CCF2F4;
$color-3: #F4F9F9;
$color-4: #AAAAAA;
$color-5: #AABBCC;
$color-6: #5499c7 ;
$color-7: #19104f ;
$color-8: #FAFAFA;
$color-9: #645b5b;
$color-10:#dddddd;
// $color-1: #4cbfa6;
@ -17,8 +20,24 @@ $color-5: #AABBCC;
// $color-6: yellow;
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
body{
background-color: #F0F0F0;
}
.imageDeProfil{
object-fit: cover;
background-size: cover;
width: 180px;
height: 180px;
clip-path:circle(50%);
}

@ -1,43 +0,0 @@
.modificationDuProfilBackgroud{
// background: $color-6;
}
.modificationDuProfil{
display: flex;
flex-direction: row;
align-items: center;
margin-left: 10%;
}
.modificationDuProfilText{
display: flex;
flex-direction: column;
padding-left:5%;
width: 88%;
font-size: medium;
}
span{
margin: 1%;
}
.imageDeProfil{
width: 15%;
}
.accesDossiersPerso{
display: flex;
align-items: row;
margin-left:10%;
width:80% ;
}
input{
margin-right: 0.5%;
}

@ -5,27 +5,27 @@
width: 140px;
height: 50px;
text-align: center;
cursor: pointer;
}
.popup-profil-container {
z-index: 100;
width: 100%;
top: 0;
left: 0;
height: 100%;
position: fixed;
animation: popup 1s forwards;
.popup-ajout-container {
position: fixed;
animation: popup 1s forwards;
z-index: 100;
left: 50%;
@keyframes popup {
from{
backdrop-filter: none;
}
to {
backdrop-filter: blur(2px);
}
}
.modal {
position: absolute;
top: 10%;
left: 50%;
transform: translate(-100%);
background: $color-2;
padding: 25px;
@ -51,6 +51,7 @@
top: 25px;
right: 25px;
transition: 0.1s;
cursor: pointer;
&:hover {
@ -59,23 +60,12 @@
}
ul {
min-width: 250px;
max-width: 300px;
margin: 20px 0 0;
max-height: 500px;
overflow-y: scroll;
overflow-x: hidden;
min-height: 200px;
&::-webkit-scrollbar {
width: 2px;
}
&::-webkit-scrollbar-track {
background: $color-4;
}
&::-webkit-scrollbar-thumb {
background: $color-1;
}
&::-webkit-scrollbar-thumb:hover {
background: #555;
}
li {
display: grid;
@ -112,3 +102,14 @@
}
}
}
#newPoste-buttonForm{
button{
color: white;
transition: all 1s;
margin-top: 2%;
border-radius: 20px;
min-width: 80px;
background-color: $color-7;
}
}

@ -0,0 +1,56 @@
.ModifucationInformationDuCompte{
display: flex;
flex-direction: row;
align-items: center;
margin-left: 10%;
}
.ModificationInformationDuCompteText{
display: flex;
flex-direction: column;
padding-left:5%;
font-size: medium;
}
.buttonSuppressionCompte{
display: flex;
flex-direction:row;
align-items:center;
button{
padding: 1%;
margin-bottom: 1%;
margin-top: 2%;
margin-left: 6%;
width: 16%;
max-width: 160px;
min-width: 120px;
background-color: $color-3;
border: 2px solid $color-4;
border-radius: 20px;
}
.buttonSuppressionText{
margin-left: 2%;
max-width: 400px;
min-width: 200px;
width: 35%;
font-style: italic;
color: red;
opacity: 70%;
background-color: $color-3;
height: fit-content;
padding: 1%;
}
button:hover {
background-color: $color-1;
border-color: black;
}
span{
padding-left: 40px;
max-width: 100px;
}
}

@ -0,0 +1,225 @@
@mixin object-center {
display: flex;
justify-content: center;
align-items: center;
}
.modificationDuProfil{
display: flex;
flex-direction: row;
align-items: center;
margin-left: 10%;
}
.modificationDuProfilText{
display: flex;
flex-direction: column;
padding-left:5%;
font-size: medium;
span{
margin-bottom: 4%;
}
}
.plusButton{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
opacity: 0;
transition: opacity 0.5s;
}
.imageDeProfilConfigurationPlus {
position: relative;
width: 15%;
max-width: 200px;
min-width: 150px;
border: none;
}
.imageDeProfilConfigurationPlus:hover .plusButton {
opacity:0.70;
}
.imageDeProfilConfiguration:hover{
filter: blur(1px);
opacity: 0.2;
transition: opacity 1s;
}
.accesDossiersPerso{
display: flex;
align-items: row;
margin-left:10%;
width:80% ;
}
input{
margin-bottom: 2%;
}
.accesDossiersPerso{
display: flex;
flex-direction: column;
}
.accesDossiersPersoValidation{
flex-direction: row;
}
.textAccesDossiersPerso{
margin-left:18px;
font-size: medium;
font-style: italic;
opacity: 70%;
}
.popup-modificationProfil{
z-index: 10;
width: 100%;
height: 100%;
top: 0;
left: 0;
position: fixed;
animation: popup 1s forwards;
@keyframes popup {
to {
backdrop-filter: blur(2px);
}
}
.modal {
position: absolute;
top: 10%;
left: 50%;
transform: translate(-100%);
background: $color-2;
padding: 25px;
border-radius: 20px;
box-shadow: 0 0 2px rgba(131, 130, 130, 0.356);
overflow: auto;
transform: scaleY(0);
transform-origin: center;
animation: modal .5s forwards;
max-width: 650px;
min-width: 500px;
border: 2px solid $color-4;
border-bottom-right-radius: 50px;
@keyframes modal {
to {
transform: scale(1) translate(-50%);
}
}
}
.imagesPopup{
display: flex;
justify-content: space-between;
flex-direction: row;
.imageModifSpace{
margin-right: 18%;
img{
max-width: initial;
}
}
.profile-pic {
position: relative;
width: 100%;
color: transparent;
transition: all .3s ease;
@include object-center;
input{
display:none;
}
img{
position: absolute;
z-index: 0;
}
.-label {
cursor: pointer;
}
&:hover {
.-label {
@include object-center;
background-color: rgba(0,0,0,.8);
z-index: 10;
color: rgb(255,255,255);
transition: background-color .2s ease-in-out;
border-radius: 20px;
margin-bottom: 0;
}
}
span {
display: inline-flex;
padding: .2em;
height: 2em;
}
}
}
.buttonPopup {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 5%;
margin-left: 8%;
margin-right: 8%;
button{
background: $color-4;
border-radius: 20px;
&:hover {
color: $color-3;
transform: translateX(2px);
}
}
}
}
.buttonValidationChangements{
position: relative;
margin-top: 2%;
border-radius: 20px;
min-width: 80px;
background-color: $color-7;
color: white;
transition: all 1s;
}
.camera{
background: url("./../../assets/img/Photo-Video-Camera-icon.png");
}
.alignementText{
margin-bottom: 2%;
}

@ -5,7 +5,7 @@
--navbar-icon-color:#646c79;
--navbar-text-color:black;
--navbar-transition-speed: .2s;
--primary-color:#7C4DFF;
--primary-color:$color-8;
--navbar-logo-background-color:#e2dfe4;
}
@ -18,7 +18,13 @@
main {
padding: 1rem 4rem;
margin-left: 5rem;
text-align: justify;
display: flex;
flex-direction: row;
justify-content: center;
}
.RightBar{
width: 20%;
}
.navbar {
@ -30,6 +36,7 @@
background:var(--navbar-background-color);
box-shadow: rgba(12,43, 30, 0.2) 0 4px 14px;
transition: width var(--navbar-transition-speed) ease;
z-index: 11;
}
.navbar:hover {

@ -1,5 +1,5 @@
.newPoste-form-popup {
background-color: white;
background-color: $color-8;
display: none;
position:fixed;
@ -38,6 +38,11 @@ textarea[name="description"]{
margin-left:10%;
margin-right:10%;
margin-bottom:10px;
margin-top:10px;
display:flex;
justify-content: space-between;
}
.postInMain{
width: 80%;
}

@ -0,0 +1,13 @@
.conteneur_notif {
display: flex;
align-items:center;
justify-content: start;
margin-top: 1%;
margin-bottom: 1%;
}
.contenue_notif:nth-child(2) {
margin-right: 10px;
}

@ -0,0 +1,49 @@
.PolitiqueDeConfidentialiteText{
display: flex;
justify-content: center;
flex-direction: column;
margin-top: 0.2%;
margin-left: 5%;
text-indent: 1%;
text-align: justify;
background-color: $color-8;
border: 0.2px solid $color-5;
max-width:85% ;
min-width: 380px;
height: 550px;
overflow-y: scroll;
scrollbar-width: thin;
scrollbar-gutter: stable both-edges;
p{
animation-duration: 1s;
animation-name: slide;
margin: 1.5%;
@keyframes slide {
from {
width: 80%;
}
to {
width: 100%;
}
}
}
}

@ -0,0 +1,57 @@
.PostesProfilConteneur{
display: flex;
flex-direction: column;
.unPosteNouvelleAffichage{
display: flex;
flex-direction: row;
justify-content: space-around;
min-height:50px ;
background: $color-8;
border: 0.3px solid $color-5;
margin: 0.2% 1%;
padding: 1% 3%;
border-radius: 10px;
.dateDePublicationDuPost{
flex: 0 0 22%;
}
.LienDunPosteNouvelleAffichage{
display: flex;
justify-content: space-between;
flex-flow: row wrap;
flex: 0.9 0 60%;
margin-left: 3%;
p{
margin-left: 5%;
}
}
.informationDunPosteNouvelleAffichage{
display: flex;
flex-direction: row;
justify-content: space-between;
padding-left: 10%;
flex: 0.5 0.4 auto;
}
}
.CommentaireProfil{
background: $color-8;
border: 0.3px solid $color-5;
}
}
.PreviewPostNouvelleAffichage{
width: 80%;
max-height: 48px;
}
.postPersonnel .dossierPersonnel{
display: flex;
flex-direction: column;
width: 100%;
}

@ -1,13 +1,31 @@
#cadrePoste{
background: white;
border: 2px solid grey;
background: $color-8;
border: 0.3px solid $color-5;
border-radius:5px;
margin-bottom: 10px;
width: 70%;
margin-bottom: 20px;
margin-left: 3%;
}
#postContenu{
padding: 15px;
}
#contenuePoste{
background: $color-8;
border: 0.3px solid $color-5;
border-radius:5px;
margin-bottom: 10px;
p{
margin-top: 0.5%;
margin: 1%;
background-color: $color-3;
border: 0.2px solid $color-5;
}
}
#hautPoste{
@ -21,11 +39,13 @@
list-style-type: none;
display: flex;
justify-content: center;
}
#cadreInfoPoste{
display: flex;
align-items:center;
}
#PhotoProfile{
margin: 0px 15px 0px 0px;
@ -47,9 +67,200 @@
justify-content: space-between;
margin-left: 10px;
margin-right: 10px;
}
#like, #commentaire{
display: flex;
align-items:center;
}
.alignementLien{
display: flex;
flex-direction: row;
justify-content: center;
background-color: $color-10;
.LienPostHome{
min-height:100px ;
height: 100%;
max-height: 300px;
}
}
.comment-container.client {
background: $color-4;
border: none;
border-radius: 20px 20px 6px 20px;
}
.comment-container {
display: grid;
grid-template-columns: 50px 1fr;
border: 1px solid $color-2;
padding: 15px;
margin: 5px 0;
border-radius: 20px 20px 20px 6px;
img {
height: 40px;
width: 40px;
border-radius: 14px;
box-shadow: 1px 1px 3px rgba(51, 51, 51, 0.192);
object-fit: cover;
}
.comment-header {
display: flex;
justify-content: space-between;
.pseudo {
display: flex;
span {
transform: translate(6px, 4px);
cursor: pointer;
img {
box-shadow: none;
height: 15px;
width: 15px;
}
}
}
span {
font-size: 0.9rem;
font-style: italic;
}
}
p {
margin-top: 8px;
}
.edit-comment {
color: $color-2;
img {
float: right;
margin-left: 10px;
cursor: pointer;
transition: 0.15s;
box-shadow: none;
height: 20px;
width: 20px;
&:hover {
transform: scale(1.1);
}
}
.edit-comment-form {
margin-top: 14px;
label {
background: white;
color: $color-1;
padding: 6px 12px 5px;
border-radius: 20px 20px 20px 6px;
cursor: pointer;
transition: 0.2s;
display: inline-block;
&:hover {
transform: scale(1.05);
}
}
input[type="text"] {
margin: 4px 0;
background: white;
font-size: 1.15rem;
padding: 16px;
width: 100%;
border-radius: 6px 20px 6px 20px;
}
.btn {
display: flex;
align-items: center;
float: right;
span {
background: white;
padding: 10px 5px;
border-radius: 50px;
margin-right: 6px;
transition: 0.2s;
cursor: pointer;
&:hover {
background: $color-2;
}
img {
transform: translate(-5px, 0);
}
}
input[type="submit"] {
background: $color-2;
width: inherit;
transition: 0.2s;
&:hover {
width: inherit;
background: $color-1;
}
}
}
}
}
}
.comment-form {
margin-top: 6px;
input[type="text"] {
width: 100%;
background: $color-4;
border-radius: 20px 20px 6px 20px;
padding: 20px;
font-size: 1.4rem;
&:focus {
box-shadow: 0 0 2px rgba(51, 51, 51, 0.5);
}
}
input[type="submit"] {
margin-top: 4px;
padding: 12px 16px;
width: 120px;
background: $color-2;
border-radius: 20px 6px 20px 20px;
transition: 0.2s;
float: right;
&:hover {
background: $color-1;
letter-spacing: 2px;
width: 130px;
}
}
button {
float: right;
background: $color-1;
transition: 0.2s;
&:hover {
background: $color-2;
}
}
}
.like-container {
span {
font-size: 1.02rem;
position: absolute;
transform: translate(8px, -1px);
}
}
.fa-share-alt {
transform: translate(0, 2px);
}

@ -5,6 +5,14 @@
@import './component/poste';
@import './pages/configuration';
@import './component/ajoutLien';
@import'./component/ConfigurationDuProfil.scss';
@import'./component/configurationDuProfil.scss';
@import'./component/configurationDuCompte.scss';
@import'./component/politiqueDeConfidentialite';
@import './component/newPoste';
@import'./component/postNouvelleAffichage';
@import './component/notif';
@import './pages/trends';

@ -1,28 +1,46 @@
.boutonDeConfigurations{
display: flex;
justify-content: center;
justify-content: space-between;
flex-direction: row;
background-color: $color-7;
margin-left: -1%;
margin-right: 1%;
button{
a{
transition: margin-right 2s,1s;
transition: background-color linear 1s,1s;
padding: 1%;
margin-bottom: 1%;
margin-top: 2%;
margin-left: 6%;
width: 16%;
max-width: 200px;
margin-top: 1%;
margin-left: 3%;
margin-right: 3%;
width: 30%;
min-width: 140px;
background-color: $color-3;
border: 2px solid $color-4;
border-radius: 20px;
text-align: center;
height: px;
}
button:hover {
background-color: $color-1;
border-color: black;
a:hover {
background-color: $color-6;
padding-right:14%;
color:$color-3;
}
}
.configuration{
input:focus{
background-color:$color-3;
}
margin-left: 6%;
}
.ligneHorizontal{
border-bottom: thick solid $color-1;
@ -32,3 +50,17 @@
margin-top: 2%;
}
.buttonValidationChangements:hover{
min-width: 100px;
padding-right: 6%;
}
// body{
// background-color: gray;
// }

@ -1,44 +1,47 @@
.ul-profil{
list-style-type: none;
display: flex;
flex-direction: column;
align-items: center;
.button-form{
cursor: pointer;
border: 3px solid black;
border-radius: 20px;
padding: 10px 5%;
transition: 0.2s;
width: 96%;
text-align: center;
margin-top: 6%;
}
.active-btn {
background: $color-3;
&:hover {
background: $color-5;
}
}
.button-form:not(.active-btn) {
&:hover {
transform: translateX(3px);
}
}
}
.info-form-container{
width: 20%;
border: 2px solid black;
background: $color-8;
border: 0.3px solid $color-5;
border-radius: 0px 15px 15px 0px;
background-color: $color-3;
p{
line-height: 15px;
letter-spacing: 1.01px;
}
.ul-profil{
list-style-type: none;
display: flex;
flex-direction: column;
align-items: center;
.button-form{
cursor: pointer;
background: $color-8;
border: 0.3px solid $color-5;
border-radius: 15px;
padding:3% 4%;
width: 96%;
text-align: center;
margin-top: 6%;
transition: all 1s;
}
.active-btn{
background: $color-8;
&:hover {
background: $color-5;
}
}
.button-form:not(.active-btn) {
&:hover {
transform: translateX(3px);
}
}
}
}
.profile-page{
@ -61,52 +64,50 @@
.cadre {
padding: 5% 10%;
border: 2px solid black;
border-right: 0px solid black;
border: 0.3px solid $color-5;
border-right: 0px;
border-radius: 15px 0px 0px 15px;
background-color: $color-1;
h1 {
letter-spacing: 5px;
margin-bottom: 30%;
margin-bottom: 15%;
font-weight: bold;
text-align: center;
}
.inputbox {
position: relative;
width: 100%;
margin-top: 4%;
margin-top: 8%;
input {
width: 100%;
border: 2px solid #000;
border: 0.3px solid $color-5;
outline: none;
background-color: $color-3;
background-color: $color-8;
padding: 4%;
border-radius: 10px;
font-size: 1.1em;
}
span {
position: absolute;
top: 12px;
left: 6%;
font-size: 1em;
top:-40%;
left: 4%;
transition: 0.3s;
font-family: sans-serif;
}
.error{
font-size: small;
font-weight: 600;
color: red;
position: absolute;
left: 6%;
}
}
.chexkboxConditionGenerale{
margin-top: 3px;
padding: 5px;
}
.error{
padding-left: 5px;
font-size: small;
font-weight: 600;
color: red;
position: absolute;
}
#connexion,#inscription{
margin-top: 5px;
}
}
@ -123,12 +124,12 @@
}
input[type="submit"], .buttonTEL{
border: none;
border-radius: 8px;
border: 2px solid #000;
background-color: $color-3;
border-radius: 10px;
background: $color-8;
border: 0.3px solid $color-5;
width: 100%;
height: 50px;
transition: background-color 1s;
}
.buttonTEL{
@ -136,6 +137,7 @@ input[type="submit"], .buttonTEL{
margin-bottom: 15px;
}
input[type="submit"]:hover, .buttonTEL:hover{
background-color: $color-5;
}
@ -151,10 +153,21 @@ input[type="submit"]:hover, .buttonTEL:hover{
}
.enregistrementReussi{
display: flex;
flex-direction: column;
width: 100%;
}
.formulaire{
width: 35%;
}
}
/*
#textSucces{
position: absolute;
width:100%;
height: 100%;
background-color: $color-5;
opacity: 80%;
color: $color-8;
visibility: hidden;
}
*/

@ -1,44 +1,44 @@
#PhotoProfile{
display: block;
margin-left: auto;
margin-right: auto;
width: 150px;
height:150px;
border-radius: 80px;
border: 2px solid #555;
}
#blocAbonnement{
display: flex;
justify-content: center;
// #PhotoProfile{
// display: block;
// margin-left: auto;
// margin-right: auto;
// width: 150px;
// height:150px;
// border-radius: 80px;
// border: 2px solid #555;
// }
// #blocAbonnement{
// display: flex;
// justify-content: center;
}
#blocAbonnement .bloc-aboonnements-abonner{
margin-left: 80px;
margin-right: 80px;
}
// }
// #blocAbonnement .bloc-aboonnements-abonner{
// margin-left: 80px;
// margin-right: 80px;
// }
#blocName{
text-align: center;
}
// #blocName{
// text-align: center;
// }
.affichage-date{
font-size: 15px;
}
// .affichage-date{
// font-size: 15px;
// }
.nombre{
color:black;
}
// .nombre{
// color:black;
// }
.texteNombre{
color:white;
}
// .texteNombre{
// color:white;
// }
#bandeauProfil{
background-color: #D9D9D9;
margin-top: 50px;
}
// #bandeauProfil{
// background-color: #D9D9D9;
// margin-top: 50px;
// }
.popup-profil-container {
z-index: 100;
@ -145,3 +145,234 @@
}
}
}
.navProfil {
margin: 0% 0 0% 4%;
padding-top: 0.5%;
}
/* Navigation */
.navProfil {
font-family: Georgia, Arial, sans-serif;
font-size: 14px;
}
.navItemsProfil {
padding-top: 2%;
padding-bottom: 2%;
list-style: none;
}
.navItemProfil {
display: inline-block;
margin-right: 25px;
}
.navLinkProfil,
.navLinkProfil:link,
.navLinkProfil:visited,
.navLinkProfil:active {
display: block;
position: relative;
font-size: 14px;
letter-spacing: 1px;
cursor: pointer;
text-decoration: none;
outline: none;
}
.navLinkProfil,
.navLinkProfil:link,
.navLinkProfil:visited,
.navLinkProfil:active {
color: black;
font-weight: bold;
}
.navLinkProfil::before {
content: "";
position: absolute;
top: 100%;
left: 0;
width: 100%;
height: 3px;
background: rgba(0,0,0,0.2);
opacity: 0;
-webkit-transform: translate(0, 10px);
transform: translate(0, 10px);
transition: opacity 0.3s ease, transform 0.3s ease;
}
.navLinkProfil:hover::before,
.navLinkProfil:hover::before {
opacity: 1;
-webkit-transform: translate(0, 5px);
transform: translate(0, 5px);
}
.image {
margin-top: 1%;
border-radius: 100%;
width: 10%;
}
.imageProfil{
display: flex;
justify-content: center;
}
.flex-menu {
display:flex;
justify-content: center;
}
.flex-menu li:not(:last-child) {
margin-right:40px;
}
.divSuivreFollowing {
display: flex;
justify-content: center;
padding-bottom: 1%;
}
.nbFollow {
margin: 0% 8% 0% 5%;
display: flex;
flex-direction: column;
justify-content: space-between;
padding-bottom: 3%;
}
.nbFollow h4 {
margin: 5% 0% 0% 0%;
display: flex;
justify-content: center;
font-weight: bold;
}
// h3 {
// margin: 0%;
// }
// h4 {
// margin: 40% 0% 0% 0%;
// display: flex;
// justify-content: center;
// font-weight: bold;
// }
.pseudo {
margin:1% 0% 0% 0%;
}
.divPseudo {
display: grid;
justify-items: center;
}
/* * {
padding:0;
margin:0;
} */
// .txtFollower {
// display: flex;
// justify-content: center;
// margin: 0%;
// padding: 0% 0% 20% 0%;
// }
.button {
padding: 0.5% 0.5%;
border-radius: 10%;
background: #19104f;
text-decoration: none;
color: white;
font-size: 16px;
letter-spacing: .08em;
margin-top: 1%;
}
.buttonReco {
padding-top: 1.5%;
border-radius: 10%;
background: #19104f;
text-decoration: none;
color: white;
font-size: 13px;
letter-spacing: .08em;
margin-top: 1%;
}
.divMenu {
margin: 0%;
background-color: #cccaca;
width: 75%;
height: 500px;
border-radius: 25px;
}
.menuContent{
border: 0.3px solid $color-5;
background-color: $color-9;
border-radius: 10px;
margin: 0% 0% 0% 2.5%;
width: 95%;
height: 85%;
}
.reco{
background-color: #a8a8a8;
margin: 0% 0% 0% 2.5%;
border-radius: 25px;
width: 100%;
height: 300px;
}
.reco span{
display: flex;
justify-content: center;
padding-top: 3%;
}
.listContent {
padding-left: 1%;
padding-top: 1%;
overflow-y: scroll;
scrollbar-width: thin;
scrollbar-gutter: stable both-edges;
}
.basDePage {
display: flex;
flex-direction: row ;
justify-content: space-around;
}
.recoDiv {
width: 20%;
}
.UtiReco {
display: flex;
flex-direction: row;
justify-content: space-evenly;
padding: 5% 0% 0% 0%;
}
.ListReco {
display: flex;
flex-direction: column;
align-content: space-around;
}
// div {
// border: 5px ridge;
// }

@ -0,0 +1,11 @@
#listeNotif{
margin: 2%;
margin-left: 20%;
padding:1%;
border-color: $color-5;
border-style:solid;
border-width: 0.3px;
min-width: 410px;
width: 60%;
background: $color-8;
}

@ -1,7 +1,7 @@
const UserModel = require('../models/user.model');
const jwt = require('jsonwebtoken');
const { signUpErrors, signInErrors } = require('../utils/errors.utils');
//const nodemailer = require('nodemailer');
const maxAge = 3 * 24 * 60 * 60 * 1000;
//expiresIn temps avant l'expiration du token
@ -12,15 +12,74 @@ const createToken = (id) => {
}
// // Définir les informations de connexion pour le service d'envoi d'e-mails
// const transporter = nodemailer.createTransport({
// service: 'gmail',
// auth: {
// user: 'mixmox07340@gmail.com',
// pass: 'Appwow07'
// }
// });
// module.exports.signUp = async (req, res) => {
// console.log(req.body);
// const {pseudo, email, password} = req.body
// try {
// const user = await UserModel.create({pseudo, email, password});
// // Générer un jeton de vérification
// const verificationToken = jwt.sign({ email }, 'secret-key', { expiresIn: '24h' });
// // Préparer l'e-mail de vérification
// const mailOptions = {
// from: 'your-email@gmail.com',
// to: email,
// subject: 'Vérifiez votre adresse e-mail',
// html: `
// <p>Veuillez cliquer sur le lien ci-dessous pour vérifier votre adresse e-mail :</p>
// <a href="http://your-website.com/verify-email?token=${verificationToken}">Cliquez ici pour vérifier</a>
// `
// };
// // Envoyer l'e-mail de vérification
// await transporter.sendMail(mailOptions);
// // Stocker le jeton de vérification associé à l'utilisateur dans la base de données
// await UserModel.updateOne({ _id: user._id }, { verificationToken });
// res.status(200).json({ user: user._id});
// }
// catch(err) {
// const errors = signUpErrors(err);
// res.status(200).send({ errors })
// }
// }
// module.exports.verifyEmail = async (req, res) => {
// const { email, token } = req.body;
// try {
// // Vérifier le jeton de vérification
// jwt.verify(token, 'secret-key', async (err, decoded) => {
// if (err) {
// return res.status(401).json({ error: 'Jeton de vérification non valide' });
// }
// if (decoded.email){
// }
// })
// }catch(err){
// }
// };
//gestion des erreurs
module.exports.signUp = async (req, res) => {
console.log(req.body);
//Attention à enlever
const {pseudo, email, password} = req.body
try {
const user = await UserModel.create({pseudo, email, password});
res.status(201).json({ user: user._id});
res.status(200).json({ user: user._id});
}
catch(err) {
const errors = signUpErrors(err);
@ -29,17 +88,29 @@ module.exports.signUp = async (req, res) => {
}
module.exports.signIn = async (req, res) => {
//console.log(req.body);
console.log("signin: ",req.body);
const {email, password} = req.body
try {
console.log("test user1 ");
const user = await UserModel.login({email, password});
console.log("test user2 ");
//creation d'un token
const token = createToken(user._id);
console.log("test user3 ");
res.cookie('jwt', token, { httpOnly: true, maxAge});
console.log("test user4 ");
res.status(200).json({ user: user._id});
}
catch(err) {
const errors = signInErrors(err);
console.log("echec test user ",errors);
res.status(200).send({ errors });
}
}

@ -0,0 +1,10 @@
const UserModel = require("../models/user.model");
const PostModel = require("../models/post.model");
module.exports.addNotification = async (userId, notification) => {
await UserModel.findByIdAndUpdate(
userId,
{ $addToSet: { notif: notification } },
{ new: true, upsert: true }
);
};

@ -7,6 +7,10 @@ const ObjectID = require("mongoose").Types.ObjectId;
const fs = require("fs");
const { promisify } = require("util");
const addNotification = require('./notifFonction');
module.exports.readPost = (req, res) => {
PostModel.find((err, docs) => {
if (!err) res.send(docs);
@ -60,7 +64,20 @@ module.exports.deletePost = (req, res) => {
});
};
module.exports.likePost = async (req, res) => {
//notif
const idUser = await PostModel.findOne({ _id: ObjectID( req.params.id) });
console.log("like",idUser);
addNotification.addNotification(idUser.postedId, {
typeNotif: "like",
id_user: req.body.id,
id_post1: req.params.id,
id_post2: "null"
});
if (!ObjectID.isValid(req.params.id))
return res.status(400).send("ID unknown : " + req.params.id);
@ -92,8 +109,9 @@ module.exports.likePost = async (req, res) => {
};
module.exports.unlikePost = async (req, res) => {
if (!ObjectID.isValid(req.params.id))
return res.status(400).send("ID unknown : " + req.params.id);
if (!ObjectID.isValid(req.params.id)) {
return res.status(400).send("ID unknown: " + req.params.id);
}
try {
await PostModel.findByIdAndUpdate(
@ -101,28 +119,55 @@ module.exports.unlikePost = async (req, res) => {
{
$pull: { likers: req.body.id },
},
{ new: true },
(err, docs) => {
if (err) return res.status(400).send(err);
}
{ new: true }
);
await UserModel.findByIdAndUpdate(
req.body.id,
{
$pull: { likes: req.params.id },
},
{ new: true },
(err, docs) => {
if (!err) return res.send(docs);
else return res.status(400).send(err);
}
{ new: true }
);
} catch (err) {
return res.status(400).send(err);
}
res.send({ message: "Post unliked" });
} catch (err) {
return res.status(400).send(err);
}
};
module.exports.commentPost = (req, res) => {
// module.exports.unlikePost = async (req, res) => {
// if (!ObjectID.isValid(req.params.id))
// return res.status(400).send("ID unknown : " + req.params.id);
// try {
// await PostModel.findByIdAndUpdate(
// req.params.id,
// {
// $pull: { likers: req.body.id },
// },
// { new: true },
// (err, docs) => {
// if (err) return res.status(400).send(err);
// }
// );
// await UserModel.findByIdAndUpdate(
// req.body.id,
// {
// $pull: { likes: req.params.id },
// },
// { new: true },
// (err, docs) => {
// if (!err) return res.send(docs);
// else return res.status(400).send(err);
// }
// );
// } catch (err) {
// return res.status(400).send(err);
// }
// };
module.exports.commentPost = async (req, res) => {
const idUser = await PostModel.findOne({ _id: ObjectID( req.params.id) });
if (!ObjectID.isValid(req.params.id))
return res.status(400).send("ID unknown : " + req.params.id);
@ -132,15 +177,22 @@ module.exports.commentPost = (req, res) => {
{
$push: {
comments: {
commenterId: req.body.commenterId,
commenterPseudo: req.body.commenterPseudo,
commentId: req.body.commenterId,
commentPseudo: req.body.commenterPseudo,
text: req.body.text,
timestamp: new Date().getTime(),
},
},
},
{ new: true })
.then((data) => res.send(data))
.then((data) => {
addNotification.addNotification(idUser.postedId, {
typeNotif: "commente",
id_user: req.body.commenterId,
id_post1: req.params.id,
id_post2: data.comments.slice(-1)[0]._id
});
res.send(data);})
.catch((err) => res.status(500).send({ message: err }));
} catch (err) {
return res.status(400).send(err);

@ -6,23 +6,30 @@ const { uploadErrors } = require('../utils/errors.utils');
module.exports.uploadProfil = async (req, res) => {
try {
console.log(req.body.file);
try {
console.log(req.body.file);
if (
req.file.detectedMimeType != "image/jpg" &&
req.file.detectedMimeType != "image/png" &&
req.file.detectedMimeType != "image/jpeg"
req.body.file.detectedMimeType != "image/jpg" &&
req.body.file.detectedMimeType != "image/png" &&
req.body.file.detectedMimeType != "image/jpeg"
)
throw Error("invalid file");
if (req.file.size > 500000) throw Error("max size");
} catch (err) {
const errors = uploadErrors(err);
return res.status(201).json({ errors });
}
const fileName = req.body.name + ".jpg";
throw Error("Invalid file format. Only jpg, jpeg, png formats are allowed.");
if (req.body.file.size > 500000) throw Error("File size exceeded the maximum limit of 500KB.");
if(req.body.file.size === 0) throw Error("Empty file");
} catch (err) {
console.log("File upload failed.")
console.log(err)
return res.status(400).json({ message: err.message });
}
const fileName = req.body.file.name + ".jpg";
await pipeline(
req.file.stream,
req.body.file.stream,
fs.createWriteStream(
`${__dirname}/../client/public/uploads/profil/${fileName}`
)
@ -30,7 +37,7 @@ module.exports.uploadProfil = async (req, res) => {
try {
await UserModel.findByIdAndUpdate(
req.body.userId,
req.body.file.userId,
{ $set: { picture: "./uploads/profil/" + fileName } },
{ new: true, upsert: true, setDefaultsOnInsert: true })
.then((data) => res.send(data))

@ -7,14 +7,24 @@ module.exports.getAllUsers = async (req, res) => {
res.status(200).json(users);
};
module.exports.getNotif = async (req, res) => {
const users = await UserModel.find().select("-password");
res.status(200).json(users);
};
//req.params par url
module.exports.userInfo = (req, res) => {
if (!ObjectID.isValid(req.params.id))
return res.status(400).send("ID unknown : " + req.params.id);
console.log('userinfo:',req.params.id)
UserModel.findById(req.params.id, (err, docs) => {
if (!err) res.send(docs);
else console.log("ID unknown : " + err);
if (!err) {
console.log('doc:',docs)
res.send(docs);
}
else
console.log("ID unknown : " + err);
}).select("-password");
};
@ -38,6 +48,24 @@ module.exports.updateUser = async (req, res) => {
}
};
// module.exports.compteUpdate = async (req,res)=>{
// const{email, password}=req.body
// try{
// await UserModel.findOneAndUpdate{
// {_id: req.params.id}
// {set:{
// email: req.body.email
// }}
// }
// }
// }
module.exports.deleteUser = async (req, res) => {
if (!ObjectID.isValid(req.params.id))
return res.status(400).send("ID unknown : " + req.params.id);
@ -51,66 +79,39 @@ module.exports.deleteUser = async (req, res) => {
};
module.exports.follow = async (req, res) => {
if (
!ObjectID.isValid(req.params.id) ||
!ObjectID.isValid(req.body.idToFollow)
)
if (!ObjectID.isValid(req.params.id) || !ObjectID.isValid(req.body.idToFollow)) {
return res.status(400).send("ID unknown : " + req.params.id);
}
try {
// add to the follower list
await UserModel.findByIdAndUpdate(
const user = await UserModel.findByIdAndUpdate(
req.params.id,
{ $addToSet: { following: req.body.idToFollow }, },
{ new: true , upsert: true },
(err, docs) => {
if (!err) return res.send(docs);
else return res.status(200).send(err);
}
)
// ajouter à la liste des followers
await UserModel.findByIdAndUpdate(
req.body.idToFollow,
{ $addToSet: { followers: req.params.id }, },
{ new: true , upsert: true},
(err, docs) => {
if (!err) return res.send(docs);
else return res.status(200).send(err);
}
);
{ $addToSet: { following: req.body.idToFollow } },
{ new: true, upsert: true }
);
const userToFollow = await UserModel.findByIdAndUpdate(
req.body.idToFollow,
{ $addToSet: { followers: req.params.id } },
{ new: true, upsert: true }
);
res.send({ user, userToFollow });
} catch (err) {
return res.status(400).send(err);
}
};
module.exports.unfollow = async (req, res) => {
if (
!ObjectID.isValid(req.params.id) ||
!ObjectID.isValid(req.body.idToUnfollow)
)
return res.status(400).send("ID unknown : " + req.params.id);
console.log(req.body.idToUnFollow);
if (!ObjectID.isValid(req.params.id) || !ObjectID.isValid(req.body.idToUnFollow)) {
return res.status(400).send("Invalid user ID: " + req.params.id);
}
try {
await userModel.findByIdAndUpdate(
req.params.id,
{ $pull: { following: req.body.idToUnfollow ,} },
{ new: true , upsert: true },
(err, docs) => {
if (err) return res.status(400).send(err);
}
);
// Retirer de la liste des followers
await userModel.findByIdAndUpdate(
req.body.idToUnfollow,
{ $pull: { followers: req.params.id } },
{ new: true , upsert: true},
(err, docs) => {
if (!err) return res.send(docs);
else return res.status(400).send(err);
}
);
await UserModel.findOneAndUpdate({ _id: req.params.id }, { $pull: { following: req.body.idToUnFollow } }, { new: true });
await UserModel.findOneAndUpdate({ _id: req.body.idToUnFollow }, { $pull: { followers: req.params.id } }, { new: true });
res.send({ message: 'unfollow successfull' });
} catch (err) {
return res.status(401).send(err);
return res.status(400).send(err);
}
}
}

@ -1,4 +1,4 @@
const mongoose = require('mongoose');
const mongoose = require('mongoose');
//trim pour supprimer les espaces
const postSchema = new mongoose.Schema(

@ -5,6 +5,25 @@ const { isEmail } = require('validator');
const bcrypt = require('bcrypt');
const NotifSchema = new mongoose.Schema({
typeNotif: {
type: String,
required: true
},
id_user: {
type: String,
required: true
},
id_post1: {
type: String,
required: true
},
id_post2: {
type: String,
required: true
}
});
//trim pour supprimer les espaces
const userSchema = new mongoose.Schema(
{
@ -32,7 +51,7 @@ const userSchema = new mongoose.Schema(
},
picture: {
type: String,
default: "/random-user.png"
default: "./random-user.png"
},
bio :{
type: String,
@ -46,7 +65,8 @@ const userSchema = new mongoose.Schema(
},
likes: {
type: [String]
}
},
notif: [NotifSchema]
},
{
timestamps: true,

File diff suppressed because it is too large Load Diff

@ -11,7 +11,7 @@
"license": "ISC",
"dependencies": {
"@reduxjs/toolkit": "^1.9.1",
"axios": "^1.2.1",
"axios": "^1.2.2",
"bcrypt": "^5.1.0",
"body-parser": "^1.20.1",
"cookie-parser": "^1.4.6",
@ -22,12 +22,15 @@
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.6.6",
"multer": "^1.4.5-lts.1",
"nodemailer": "^6.9.0",
"nodemon": "^2.0.20",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.4.5",
"react-router-dom": "^6.6.1",
"react-scripts": "^5.0.1",
"sass": "^1.56.2",
"sass": "^1.57.1",
"tachyons": "^4.12.0",
"validator": "^13.7.0"
"validator": "^13.7.0",
"web-vitals": "^3.1.0"
}
}

@ -9,18 +9,20 @@ const upload = multer();
//controlleur d'authentification
router.post('/register', authController.signUp);
router.post('/login', authController.signIn);
//router.post('/send-verification-email', authController.verifEmail);
//retirer le token (cookie)
router.get('/logout', authController.logout);
// user
router.get('/', userController.getAllUsers);
router.get('/:id', userController.userInfo);
//put pour faire des updates
router.put("/:id", userController.updateUser);
router.put('/:id', userController.updateUser);
router.delete('/:id', userController.deleteUser);
router.patch('/follow/:id', userController.follow);
router.patch('/unfollow/:id', userController.unfollow);
router.patch('/notif/:id', userController.getNotif);
//upload pb avec postman
router.post("/upload", upload.single('file'), uploadController.uploadProfil);

@ -32,24 +32,17 @@ module.exports.signInErrors = (err) => {
}
module.exports.uploadErrors = (err) => {
let errors = { format: '', maxSize: ""};
let errors = { format: '', maxSize: "",empty:""};
if (err.message.includes('invalid file'))
errors.format = "Format incompatabile";
if (err.message.includes('max size'))
errors.maxSize = "Le fichier dépasse 500ko";
if(err.message.includes('empty file'))
errors.empty ="Le fichier est vide";
return errors
}
module.exports.uploadErrors = (err) => {
let errors = { format: '', maxSize: ""};
if (err.message.includes('invalid file'))
errors.format = "Format incompatible";
if (err.message.includes('max size'))
errors.maxSize = "Le fichier dépasse 500ko";
return errors;
}

Binary file not shown.
Loading…
Cancel
Save