Affichage post

post
Noan07 2 years ago
parent b7982ff0f0
commit 29c32b2203

@ -0,0 +1 @@
/node_modules

@ -9,12 +9,14 @@
name="description" name="description"
content="Web site created using create-react-app" content="Web site created using create-react-app"
/> />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> --> <!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.

@ -3,7 +3,7 @@ import { UidContext } from "./components/AppContext";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import axios from "axios"; import axios from "axios";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { setPictureData } from "./feature/pictures.slice"; import { getUser } from "./actions/user.actions";
//useeffect controle le token de l'utilisateur //useeffect controle le token de l'utilisateur
//les crochets dans le use effect permette de pas lancer la fonction à l'infini //les crochets dans le use effect permette de pas lancer la fonction à l'infini
@ -22,11 +22,12 @@ function App() {
.catch((err) => console.log("No Token")); .catch((err) => console.log("No Token"));
}; };
fetchToken(); fetchToken();
if (uid){ if(uid) dispatch(getUser(uid));
/*if (uid){
axios axios
.get(`${process.env.REACT_APP_API_URL}api/user/${uid}`) .get(`${process.env.REACT_APP_API_URL}api/user/${uid}`)
.then((res) => dispatch(setPictureData(res.data))) .then((res) => dispatch(setPictureData(res.data)))
}; };*/
}, [uid, dispatch]); }, [uid, dispatch]);

@ -0,0 +1,134 @@
import axios from "axios";
import { setPostError } from "../reducers/error.reducer";
import { setPostData, setPostLikeData, setPostUnLikeData } from "../reducers/post.reducer";
export const getPosts = () => {
return (dispatch) => {
return axios
.get(`${process.env.REACT_APP_API_URL}api/post/`)
.then((res) => {
dispatch(setPostData(res.data));
})
.catch((err) => console.log(err))
}
}
export const likePost = (postId, userId) => {
return (dispatch) => {
return axios({
method: 'patch',
url: `${process.env.REACT_APP_API_URL}api/post/like-post/` + postId,
data: { id: userId },
})
.then((res) => {
dispatch(setPostLikeData({payload:{ postId, userId }}));
})
.catch((err) => console.log(err))
}
}
export const unlikePost = (postId, userId) => {
return (dispatch) => {
return axios({
method: 'patch',
url: `${process.env.REACT_APP_API_URL}api/post/unlike-post/` + postId,
data: { id: userId },
})
.then((res) => {
//dispatch(setPostUnLikeData({ postId, userId }));
})
.catch((err) => console.log(err))
}
}
export const addPost = (data) => {
console.log(data,"test")
return (dispatch) => {
return axios
.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: "" }));
// }
});
};
};
// // export const updatePost = (postId, message) => {
// // return (dispatch) => {
// // return axios({
// // method: "put",
// // url: `${process.env.REACT_APP_API_URL}api/post/${postId}`,
// // data: { message },
// // })
// // .then((res) => {
// // dispatch({ type: UPDATE_POST, payload: { message, postId } });
// // })
// // .catch((err) => console.log(err));
// // };
// // };
// export const deletePost = (postId) => {
// return (dispatch) => {
// return axios({
// method: "delete",
// url: `${process.env.REACT_APP_API_URL}api/post/${postId}`,
// })
// .then((res) => {
// dispatch({ type: DELETE_POST, payload: { postId } });
// })
// .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 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 });
// };
// };

@ -0,0 +1,61 @@
import axios from "axios";
import { setUserData, setUserDataImg, setUserToFollowData, setUserToUnFollowData } from "../reducers/user.reducer";
export const getUser = (uid) => {
return (dispatch)=> {
return axios
.get(`${process.env.REACT_APP_API_URL}api/user/${uid}`)
.then((res) => {
dispatch(setUserData(res.data))
})
.catch((err) => console.log(err));
};
};
export const uploadPicture = (data, id) => {
return (dispatch) => {
return axios
.post(`${process.env.REACT_APP_API_URL}api/user/upload`,data)
.then((res) => {
return axios
.get(`${process.env.REACT_APP_API_URL}api/user/${id}`)
.then((res) => {
dispatch(setUserDataImg(res.data.picture));
})
})
.catch((err) => console.log(err));
};
};
export const followUser = (followerId, idToFollow) => {
return async (dispatch) => {
try {
const res = await axios({
method: "patch",
url: `${process.env.REACT_APP_API_URL}api/user/follow/` + followerId,
data: { idToFollow },
});
dispatch(setUserToFollowData({payload: { idToFollow }}));
} catch (err) {
return console.log(err);
}
};
};
export const unFollowUser = (followerId, idToUnFollow) => {
return (dispatch) => {
return axios({
method: "patch",
url: `${process.env.REACT_APP_API_URL}api/user/unfollow/` + followerId,
data: { idToUnFollow },
})
.then((res) => {
dispatch(setUserToUnFollowData({payload: {idToUnFollow}}));
})
.catch((err) => console.log(err));
};
};

@ -0,0 +1,14 @@
import axios from "axios";
import { setUsersData } from "../reducers/users.reducer";
export const getUsers = () => {
return (dispatch) => {
return axios
.get(`${process.env.REACT_APP_API_URL}api/user`)
.then((res) => {
dispatch(setUsersData(res.data));
})
.catch((err) => console.log(err));
};
};

@ -1,18 +1,115 @@
import React, {useState} from 'react'; import axios from 'axios';
import NewPoste from "./NewPoste"; import React, {useContext, useState} from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { addPost, getPosts } from '../actions/post.actions';
import { UidContext } from './AppContext';
const AjoutLien = () => { const AjoutLien = () => {
const uid = useContext(UidContext);
const userData = useSelector((state) => state.user.user);
const [displayAdd, setDisplayAdd] = useState(false);
const [lien, setLien] = useState("");
const [description, setDescription] = useState("");
const dispatch = useDispatch();
const handleModals = (e) => { const handlePost = async () => {
<NewPoste/> if(isValidUrl(lien))
if ((description || lien) ){
putData();
dispatch(getPosts());
cancelPost();
setDisplayAdd(false);
window.location.reload();
}else {
alert("Veuillez compléter tous les champs.")
}
else{
alert("Ce n'est pas lien!")
}
};
const cancelPost = () => {
setDescription("");
setLien("");
};
const putData = async() => {
axios
.post(`${process.env.REACT_APP_API_URL}api/post/`, { postedId: userData._id, message: description, lien: lien}
)
.then((res) => {
// if (res.data.errors) {
// dispatch(setPostError({payload: res.data.errors }));
// } else {
// dispatch(setPostError({payload: "" }));
// }
})};
const isValidUrl = (url) => {
try {
new URL(url);
return true;
}catch {
return false;
}
} }
return ( return (
<div className='ajoutLien'> <>
<button className="bouttonAjoutLien" id="display" type='bouton' onClick={handleModals}> <div className='ajoutLien'>
Poster un lien {uid === null &&
</button> <button className="bouttonAjoutLien" id="display" type='bouton'>
</div> Se connecter
</button>
}
{uid !== null &&
<button className='button-add-link' onClick={() => setDisplayAdd(true)} >
Poster un lien
</button>
}
</div>
{displayAdd && (
<div className="popup-profil-container">
<div className="modal">
<h3>Ajout d'un lien</h3>
<span className="cross" onClick={() => setDisplayAdd(false)}>
&#10005;
</span>
<ul>
<form className="newPoste-form-container">
<div className="newPoste-input">
<input type="text"
placeholder="Votre lien!"
onChange={(e) => setLien(e.target.value)}
value={lien}
required />
</div>
<div className="newPoste-input">
<textarea type="text"
row="250"
placeholder="Description de votre post"
onChange={(e) => setDescription(e.target.value)}
value={description}
required
/>
</div>
<div id="newPoste-buttonForm">
<div>
<button onClick={() => setDisplayAdd(false)} className="newPoste-btn-cancel" >retour</button>
</div>
<div>
<button onClick={handlePost} className="newPoste-btn">Poster</button>
</div>
</div>
</form>
</ul>
</div>
</div>
)}
</>
); );
}; };

@ -1,9 +1,11 @@
import React from 'react'; import React from 'react';
import PP from "../../assets/img/unknown.png"; import PP from "../../assets/img/unknown.png";
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import { useSelector } from 'react-redux';
const ConfigurationDuProfil = ()=>{ const ConfigurationDuProfil = ()=>{
const userData = useSelector((state) => state.userReducer)
return( return(
<div> <div>

@ -5,18 +5,17 @@ import { NavLink } from "react-router-dom";
const PolitiqueDeConfidentialite =()=>{ const PolitiqueDeConfidentialite =()=>{
return( return(
<div> <div>
Cette politique de confidentialité sapplique au site : Designed By GG. 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 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 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 ; 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 ; Quels sont les droits des utilisateurs concernant ces données ;
Qui est responsable du traitement des données à caractère personnes Qui est responsable du traitement des données à caractère personnes
collectées et traitées ; collectées et traitées ;
A qui ces données sont transmises ; A qui ces données sont transmises ;
Eventuellement, la politique du site en matière de fichiers cookies Eventuellement, la politique du site en matière de fichiers cookies
</div> </div>
) )
} }

@ -1,18 +1,66 @@
import { NavLink } from "react-router-dom"; import { NavLink } from "react-router-dom";
import { UidContext } from "./AppContext"; import { UidContext } from "./AppContext";
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { useSelector } from "react-redux"; import { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import PP from "../assets/img/unknown.png"; import PP from "../assets/img/unknown.png";
import cookie from 'js-cookie'; import cookie from 'js-cookie';
import axios from "axios"; import axios from "axios";
import Logo from "../assets/img/logo.png"; import Logo from "../assets/img/logo.png";
import Configuration from "./../pages/Configuration"; import { addPost, getPosts } from "../actions/post.actions";
const Navbar = () => { const Navbar = () => {
const uid = useContext( UidContext ); const uid = useContext( UidContext );
const userData = useSelector((state) => state.pictures.pictures); const userData = useSelector((state) => state.user.user);
const [displayAdd, setDisplayAdd] = useState(false);
const [lien, setLien] = useState("");
const [description, setDescription] = useState("");
const dispatch = useDispatch();
const handlePost = () => {
if ((description || lien) ){
const data = new FormData();
data.append('postedId', userData._id);
data.append('message', description);
data.append('lien', lien);
console.log(data);
putData(data);
console.log(data);
cancelPost();
setDisplayAdd(false)
}else {
alert("Veuillez compléter tous les champs.")
}
};
const putData = async(data) => {
axios
.post(`${process.env.REACT_APP_API_URL}api/post/`, { postedId: userData._id, message: description, lien: lien}
)
.then((res) => {
console.log(data,"test");
// if (res.data.errors) {
// dispatch(setPostError({payload: res.data.errors }));
// } else {
// dispatch(setPostError({payload: "" }));
// }
})};
const cancelPost = () => {
setDescription("");
setLien("");
};
const isValidUrl = (url) => {
try {
new URL(url);
return true;
}catch {
return false;
}
}
const removeCookie = (key) => { const removeCookie = (key) => {
if(window !== "undefined"){ if(window !== "undefined"){
cookie.remove(key, {expires: 1} ); cookie.remove(key, {expires: 1} );
@ -34,68 +82,116 @@ const Navbar = () => {
return ( return (
<div> <div>
{uid ? ( {uid ? (
<header>
<nav> <nav className="navbar">
<ul className="partie-gauche-nav ul-navBar"> <ul className="navbar-menu">
<li className="logo"> <li className="navbar-item logo">
<img src={Logo} height="30px" alt='Logo'/> <NavLink to="/Home" className="navbar-link">
</li> <span className="navbar-title">Favor</span>
</ul> <i className="fas fa-chevron-right navbar-icon"></i>
<ul className="ul-navBar"> </NavLink>
<li> </li>
<NavLink to="/Discover" className={((nav) => (nav.isActive ? "nav-active b nav-active-tendances-decouvrir" : "b"))}> <li className="navbar-item">
<span>Découvrir</span> <NavLink to="/Home" className="navbar-link">
</NavLink> <i className="fas fa-home navbar-icon"></i>
</li> <span className="navbar-title">Home</span>
</NavLink>
</li>
<li className="navbar-item">
<NavLink to="/Discover" className="navbar-link">
<i className="fas fa-bullseye navbar-icon"></i>
<span className="navbar-title">Découvrir</span>
</NavLink>
</li>
<li className="navbar-item">
<NavLink to="/Trends" className="navbar-link">
<i className="fas fa-bell navbar-icon"></i>
<span className="navbar-title">Notifications</span>
</NavLink>
</li>
<li className="navbar-item">
<NavLink to="/Profil" 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">
<i className="fas fa-cog navbar-icon"></i>
<span className="navbar-title">Paramètre</span>
</a>
</li>
<li className="navbar-item">
<a onClick={logout} className="navbar-link">
<i className="fas fa-sign-out-alt navbar-icon"></i>
<span className="navbar-title">Déconnexion</span>
</a>
</li>
</ul>
</nav>
// <header>
// <nav>
// <ul className="partie-gauche-nav ul-navBar">
// <li className="logo">
// <img src={Logo} height="30px" alt='Logo'/>
// </li>
// </ul>
// <ul className="ul-navBar">
// <li>
// <NavLink to="/Discover" className={((nav) => (nav.isActive ? "nav-active b nav-active-tendances-decouvrir" : "b"))}>
// <span>Découvrir</span>
// </NavLink>
// </li>
<li> // <li>
<NavLink to="/Home" className={((nav) => (nav.isActive ? "nav-active b nav-active-menu" : "b"))}> // <NavLink to="/Home" className={((nav) => (nav.isActive ? "nav-active b nav-active-menu" : "b"))}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" className="svg-home"> // <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" className="svg-home">
<path stroke="black" fill='black' d="M256 73.825a182.18 182.18 0 0 0-182.18 182.18c0 100.617 81.567 182.17 182.18 182.17a182.175 182.175 0 1 0 0-364.35zm76.636 161.579h-12.037v91.503a18.908 18.908 0 0 1-18.896 18.904h-26.78v-53.56a6.299 6.299 0 0 0-6.297-6.294H232.4a6.3 6.3 0 0 0-6.302 6.294v53.56h-26.771a18.91 18.91 0 0 1-18.906-18.904v-91.503h-11.97a7.879 7.879 0 0 1-5.071-13.905l82.055-69.039a7.89 7.89 0 0 1 10.142 0l81.479 68.547a7.88 7.88 0 0 1-4.421 14.396z" data-name="Home"/> // <path stroke="black" fill='black' d="M256 73.825a182.18 182.18 0 0 0-182.18 182.18c0 100.617 81.567 182.17 182.18 182.17a182.175 182.175 0 1 0 0-364.35zm76.636 161.579h-12.037v91.503a18.908 18.908 0 0 1-18.896 18.904h-26.78v-53.56a6.299 6.299 0 0 0-6.297-6.294H232.4a6.3 6.3 0 0 0-6.302 6.294v53.56h-26.771a18.91 18.91 0 0 1-18.906-18.904v-91.503h-11.97a7.879 7.879 0 0 1-5.071-13.905l82.055-69.039a7.89 7.89 0 0 1 10.142 0l81.479 68.547a7.88 7.88 0 0 1-4.421 14.396z" data-name="Home"/>
</svg> // </svg>
</NavLink> // </NavLink>
</li> // </li>
<li> // <li>
<NavLink to="/Trends" className={((nav) => (nav.isActive ? "nav-active b nav-active-tendances-decouvrir" : "b"))}> // <NavLink to="/Trends" className={((nav) => (nav.isActive ? "nav-active b nav-active-tendances-decouvrir" : "b"))}>
<span>Tendances</span> // <span>Tendances</span>
</NavLink> // </NavLink>
</li> // </li>
</ul> // </ul>
<ul className="partie-droit-nav ul-navBar"> // <ul className="partie-droit-nav ul-navBar">
<li > // <li >
<NavLink to="/Profil" className='b'> // <NavLink to="/Profil" className='b'>
{ (userData==null) ? (<span></span>):(<span>{userData.pseudo}</span>)} // { (userData==null) ? (<span></span>):(<span>{userData.pseudo}</span>)}
</NavLink> // </NavLink>
</li> // </li>
<li> // <li>
<NavLink to="/Profil" className='b'> // <NavLink to="/Profil" className='b'>
<img src={PP} alt='Logo' className="img-profile"/> // <img src={PP} alt='Logo' className="img-profile"/>
</NavLink> // </NavLink>
</li> // </li>
<li> // <li>
<div className='b more'> // <div className='b more'>
<div className="menu-deroulant"> // <div className="menu-deroulant">
<svg xmlns="http://www.w3.org/2000/svg" className="svg-param" viewBox="0 0 256 256"> // <svg xmlns="http://www.w3.org/2000/svg" className="svg-param" viewBox="0 0 256 256">
<path d="M128,24A104,104,0,1,0,232,128,104.11791,104.11791,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.09957,88.09957,0,0,1,128,216Zm12-88a12,12,0,1,1-12-12A12.01375,12.01375,0,0,1,140,128Zm48,0a12,12,0,1,1-12-12A12.01375,12.01375,0,0,1,188,128Zm-96,0a12,12,0,1,1-12-12A12.01375,12.01375,0,0,1,92,128Z"/> // <path d="M128,24A104,104,0,1,0,232,128,104.11791,104.11791,0,0,0,128,24Zm0,192a88,88,0,1,1,88-88A88.09957,88.09957,0,0,1,128,216Zm12-88a12,12,0,1,1-12-12A12.01375,12.01375,0,0,1,140,128Zm48,0a12,12,0,1,1-12-12A12.01375,12.01375,0,0,1,188,128Zm-96,0a12,12,0,1,1-12-12A12.01375,12.01375,0,0,1,92,128Z"/>
</svg> // </svg>
</div> // </div>
<div className="more-menu"> // <div className="more-menu">
<NavLink className='element-menu-deroulant' to="/Configuration">Configurations</NavLink> // <NavLink className='element-menu-deroulant' to="/Configuration">Configurations</NavLink>
<NavLink className='element-menu-deroulant'>Élement 2</NavLink> // <a onClick={() => setDisplayAdd(true)} className='element-menu-deroulant'>Élement 2</a>
<NavLink className='element-menu-deroulant' onClick={logout}>Élement 3</NavLink> // <NavLink className='element-menu-deroulant' onClick={logout}>Élement 3</NavLink>
</div> // </div>
</div> // </div>
</li> // </li>
</ul> // </ul>
</nav> // </nav>
</header> // </header>
) : (<div> </div> ) : (<div> </div>
)} )}
</div> </div>
); );
}; };

@ -3,26 +3,28 @@ import React, { useState } from 'react';
//e.preventDefaul(); pour ne pas recharcher la page //e.preventDefaul(); pour ne pas recharcher la page
const NewPoste = (props) => { const NewPoste = ({ post }) => {
return ( return (
<div> <div>
<div class="newPoste-form-popup" id="newPoste-popupFormulaireCreationPoste"> <div className="newPoste-form-popup" id="newPoste-popupFormulaireCreationPoste">
<form action="/action_page.php" class="newPoste-form-container"> <form action="/action_page.php" className="newPoste-form-container">
<div class="newPoste-input"> <div className="newPoste-input">
<label for="lien">Lien:</label> {/* <label for="lien">Lien:</label> */}
<input type="text" name="lien" required /> <input type="text" name="lien" required />
</div> </div>
<div class="newPoste-input"> <div className="newPoste-input">
<label for="description">Description:</label> {/* <label for="description">Description:</label> */}
<textarea name="description" row="250"></textarea> <textarea name="description" row="250"></textarea>
</div> </div>
<div id="newPoste-buttonForm"> <div id="newPoste-buttonForm">
<div> <div>
<button type="button" class="newPoste-btn-cancel" onclick="closeForm()">retour</button> {/* <button type="button" className="newPoste-btn-cancel" onclick="closeForm()">retour</button> */}
<button type="button" className="newPoste-btn-cancel" >retour</button>
</div> </div>
<div> <div>
<button type="submit" class="newPoste-btn">Poster</button> <button type="submit" className="newPoste-btn">Poster</button>
</div> </div>
</div> </div>
</form> </form>

@ -0,0 +1,40 @@
import React, { useContext, useEffect, useState } from 'react';
import { UidContext } from "../AppContext";
import { useDispatch } from 'react-redux';
import Coeur from '../../assets/img/coeurs.png';
import CoeurPlein from '../../assets/img/coeursPlein.png';
import { likePost, unlikePost } from '../../actions/post.actions';
const ButtonLike = ( { post } ) => {
const [liked, setLiked] = useState(false);
const uid = useContext(UidContext);
const dispatch = useDispatch();
const like = () => {
dispatch(likePost(post._id, uid))
setLiked(true);
};
const unlike = () => {
dispatch(unlikePost(post._id, uid))
setLiked(false);
};
useEffect(() => {
if (post.likers.includes(uid)) setLiked(true);
else setLiked(false);
}, [uid, post.likers, liked]);
return (
<div>
{uid && liked === false && (
<img src={Coeur} onClick={like} alt="like" />
)}
{uid && liked && (
<img src={CoeurPlein} onClick={unlike} alt="unlike" />
)}
</div>
);
};
export default ButtonLike;

@ -0,0 +1,33 @@
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { getPosts } from '../../actions/post.actions';
import NewPoste from '../NewPoste';
import { isEmpty } from "../Utils";
import Post from './Post';
const DisplayPosts = () => {
const [loadPost, setLoadPost] = useState(true);
const [count , setCount] = useState(5);
const dispatch = useDispatch();
const postsData = useSelector((state) => state.post.post);
useEffect(() => {
if (loadPost) {
dispatch(getPosts());
setLoadPost(false);
}
}, [loadPost,dispatch])
return (
<div>
<ul>
{!isEmpty(postsData[0]) &&
postsData.map((post) => {
return <Post post={post} key={post._id}/>
})}
</ul>
</div>
);
};
export default DisplayPosts;

@ -0,0 +1,76 @@
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';
//e.preventDefaul(); pour ne pas recharcher la page
const Post = ( { post } ) => {
const [isLoading, setIsLoading] = useState(true);
const usersData = useSelector((state) => state.users.users);
const userData = useSelector((state) => state.user.user);
useEffect(() => {
!isEmpty(usersData[0]) && setIsLoading(false)
})
return (
<li className='conteneur_postes' key={post._id}>
{isLoading ? (
<i className='fas fa-spinner fa-spin'></i>
):(
<div id="cadrePoste">
<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'}/>)} */}
</div>
<div>{dateParser(post.createdAt)}</div>
</div>
<div id="contenuePoste">
/*utliser leakpreview*/
</div>
<div id="contenuePoste">
<p>{post.message}</p>
</div>
<div id="basPoste">
<div id="like">
<ButtonLike post={post}/>
{/* <img src="coeurs.png"/> */}
<div>{post.likers.length}</div>
</div>
<div id="commentaire">
<img src="commentaire.png"/>
<div>{post.comments.length}</div>
</div>
</div>
</div>
</div>) }
</li>
);
};
//ce qui écrit dans le input est récuperé par le state
export default Post;

@ -1,36 +0,0 @@
import axios from 'axios';
import React, { useState } from 'react';
//e.preventDefaul(); pour ne pas recharcher la page
const Poste = (props) => {
return (
<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>
);
};
//ce qui écrit dans le input est récuperé par le state
export default Poste;

@ -12,7 +12,7 @@ const index = () => {
<BrowserRouter> <BrowserRouter>
<Routes> <Routes>
<Route path="/" element={<HomeNavigation/>} /> <Route path="/" element={<HomeNavigation/>} />
<Route path="/home" element={<Home/>} /> <Route path="/h" element={<Home/>} />
<Route path="/trends" element={<Trends/>} /> <Route path="/trends" element={<Trends/>} />
<Route path="/discover" element={<Discover/>} /> <Route path="/discover" element={<Discover/>} />
<Route path="*" element={<HomeNavigation/>} /> <Route path="*" element={<HomeNavigation/>} />

@ -0,0 +1,71 @@
import axios from 'axios';
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { followUser, unFollowUser } from '../../actions/user.actions';
import { setUserToFollowData, setUserToUnFollowData } from '../../reducers/user.reducer';
import { isEmpty } from '../Utils';
const FollowHandler = ( { idToFollow , type } ) => {
const userData = useSelector((state) => state.user.user);
const [isFollowed, setIsFollowed] = useState(false);
const dispatch = useDispatch();
const handleFollow = () => {
axios.patch(`${process.env.REACT_APP_API_URL}api/user/follow/` + userData._id, {params: {idToFollow: idToFollow}} )
.then((res) => {
//dispatch(setUserToFollowData({payload: {idToFollow}}));
})
.catch((err) => console.log(err));
setIsFollowed(false);
};
const handleUnFollow = () => {
axios.patch(`${process.env.REACT_APP_API_URL}api/user/unfollow/` + userData._id, {params: {idToFollow: idToFollow}} )
.then((res) => {
// dispatch(setUserToUnFollowData({payload: {idToFollow}}));
})
.catch((err) => console.log(err));
setIsFollowed(false);
};
// const handleFollow = () => {
// dispatch(followUser(userData._id, idToFollow))
// setIsFollowed(true);
// }
// const handleUnFollow = () => {
// dispatch(unFollowUser(userData._id, idToFollow))
// setIsFollowed(false);
// }
useEffect(() => {
if(!isEmpty(userData.following)) {
if(userData.following.includes(idToFollow)) {
setIsFollowed(true);
} else setIsFollowed(false);
}
}, [userData,idToFollow])
return (
<>
{isFollowed && !isEmpty(userData) && (
<span onClick={handleUnFollow}>
{type === "card" && <button className="unfollow-btn">Abonné</button>}
{type === "suggest" && <i className="fas fa-check-circle navbar-icon"></i>}
</span>
)}
{isFollowed === false && !isEmpty(userData) && (
<span onClick={handleFollow}>
{type === "card" && <button className="follow-btn">Suivre</button>}
{type === "suggest" && <i className="far fa-check-circle navbar-icon"></i>}
</span>
)}
</>
);
};
export default FollowHandler;

@ -0,0 +1,29 @@
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
const UploadImage = () => {
const [file,setFile] =useState();
//pour envoyer l'image
const dispatch = useDispatch();
const userData = useSelector((state) => state.user.user)
const handlePicture = (e) => {
e.preventDefault();
const data = new FormData();
data.append("name", userData.pseudo);
data.append("userId", userData._id);
data.append("file",file);
dispatch(uploadPicture(data, userData._id));
}
return (
<form action="" onSubmit={handlePicture} className="">
<label htmlFor='file'>Changer d'image</label>
<input type="file" id="file" accept='.jpg, .jpeg, .png' onChange={(e) => setFile(e.target.files[0])}/>
<br/>
<input type="submit" value="Send"/>
</form>
);
};
export default UploadImage;

@ -0,0 +1,39 @@
export const isEmpty = (value) => {
return ( value === 'string ' || value === null ||
(typeof value === "object" && Object.keys(value).length === 0) ||
(typeof value === "string" && value.trim().length === 0) );
};
export const dateParser = (num) => {
let options = {
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
weekday: "long",
year: "numeric",
month: "short",
day: "numeric",
};
let timestamp = Date.parse(num);
let date = new Date(timestamp).toLocaleDateString("fr-FR", options);
return date.toString();
};
export const timestampParser = (num) => {
let options = {
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
weekday: "long",
year: "numeric",
month: "short",
day: "numeric",
};
let date = new Date(num).toLocaleDateString("fr-FR", options);
return date.toString();
}

@ -1,18 +0,0 @@
import { createSlice } from "@reduxjs/toolkit";
export const picturesSlice = createSlice({
name: "pictures",
initialState: {
pictures: null,
},
reducers: {
setPictureData: (state,action) => {
state.pictures = action.payload;
},
},
});
export const {setPictureData} = picturesSlice.actions;
export default picturesSlice.reducer;

@ -3,8 +3,13 @@ import ReactDOM from 'react-dom/client';
import App from './App'; import App from './App';
import "./styles/index.scss"; import "./styles/index.scss";
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import store from './app/store'; //import store from './app/store';
import store from './reducers/index';
import { getPosts } from './actions/post.actions';
import { getUsers } from './actions/users.actions';
store.dispatch(getUsers());
store.dispatch(getPosts());
const root = ReactDOM.createRoot(document.getElementById('root')); const root = ReactDOM.createRoot(document.getElementById('root'));
root.render( root.render(

@ -1,9 +1,21 @@
import React from 'react'; import React from 'react';
import AjoutLien from '../components/AjoutLien';
import Navbar from '../components/Navbar'; import Navbar from '../components/Navbar';
import DisplayPosts from '../components/Post/DisplayPosts';
const Discover = () => { const Discover = () => {
return ( return (
<Navbar /> <>
<Navbar />
<main >
<div className='postInMain'>
<DisplayPosts/>
</div>
<div className="RightBar">
<AjoutLien/>
</div>
</main>
</>
); );
}; };

@ -1,12 +1,20 @@
import React from 'react'; import React from 'react';
import AjoutLien from '../components/AjoutLien'; import AjoutLien from '../components/AjoutLien';
import DisplayPosts from '../components/Post/DisplayPosts';
import Navbar from '../components/Navbar'; import Navbar from '../components/Navbar';
const Home = () => { const Home = () => {
return ( return (
<> <>
<Navbar /> <Navbar />
<AjoutLien/> <main >
<div className='postInMain'>
<DisplayPosts/>
</div>
<div className="RightBar">
<AjoutLien/>
</div>
</main>
</> </>
); );
}; };

@ -20,8 +20,6 @@ const HomeNavigation = () => {
<Log signin={true} signup={false}/> <Log signin={true} signup={false}/>
</div> </div>
)} )}
<AjoutLien></AjoutLien>
<NewPoste></NewPoste>
</div> </div>
); );
}; };

@ -1,13 +1,22 @@
import React from 'react'; import {React, useState} from 'react';
import { useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import Navbar from '../components/Navbar'; import Navbar from '../components/Navbar';
import { dateParser } from '../components/Utils';
import FollowHandler from '../components/UserProfil/FollowHandler';
const Profil = () => { const Profil = () => {
const userData = useSelector((state) => state.pictures.pictures); const userData = useSelector((state) => state.user.user);
const usersData = useSelector((state) => state.users.users);
const dispatch = useDispatch();
const [followingPopup, setFollowingPopup] = useState(false);
const [followerPopup, setFollowerPopup] = useState(false);
return ( return (
<> <>
<Navbar /> <Navbar />
<main>
<div id="bandeauProfil"> <div id="bandeauProfil">
<h1 className='affichage-date'>Compte créé le : {dateParser(userData.createdAt)}</h1>
<div id="image"> <div id="image">
<img id="PhotoProfile" alt="Profil" src={userData.picture}/> <img id="PhotoProfile" alt="Profil" src={userData.picture}/>
</div> </div>
@ -16,18 +25,76 @@ const Profil = () => {
<h2 className="subdo">@{userData.pseudo}</h2> <h2 className="subdo">@{userData.pseudo}</h2>
<div> <div>
<div id="blocAbonnement"> <div id="blocAbonnement">
<div> <div onClick={() => setFollowingPopup(true)} className="bloc-aboonnements-abonner">
<div className="nombre">{userData.following.length}</div> <div className="nombre">{userData.following.length}</div>
<div className="texteNombre">Abonnement</div> <div className="texteNombre">Abonnement</div>
</div> </div>
<div> <div onClick={() => setFollowerPopup(true)} className="bloc-aboonnements-abonner">
<div className="nombre">{userData.followers.length}</div> <div className="nombre">{userData.followers.length}</div>
<div className="texteNombre">Abonnée</div> <div className="texteNombre">Abonnée</div>
</div> </div>
{followingPopup && (
<div className="popup-profil-container">
<div className="modal">
<h3>Abonnements</h3>
<span className="cross" onClick={() => setFollowingPopup(false)}>
&#10005;
</span>
<ul>
{usersData.map((user) => {
for (let i = 0; i < userData.following.length; i++) {
if (user._id === userData.following[i]) {
return (
<li key={user._id}>
<img src={user.picture} alt="user-pic" />
<h4>{user.pseudo}</h4>
<div className="follow-handler">
<FollowHandler idToFollow={user._id} type={'card'}/>
</div>
</li>
);
}
}
return null;
})}
</ul>
</div>
</div>
)}
{followerPopup && (
<div className="popup-profil-container">
<div className="modal">
<h3>Abonnés</h3>
<span className="cross" onClick={() => setFollowerPopup(false)}>
&#10005;
</span>
<ul>
{usersData.map((user) => {
for (let i = 0; i < userData.followers.length; i++) {
if (user._id === userData.followers[i]) {
return (
<li key={user._id}>
<img src={user.picture} alt="user-pic" />
<h4>{user.pseudo}</h4>
<div className="follow-handler">
<FollowHandler idToFollow={user._id} type={'card'} />
</div>
</li>
);
}
}
return null;
})}
</ul>
</div>
</div>
)}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</main>
</> </>
) )
}; };

@ -0,0 +1,23 @@
import { createSlice } from "@reduxjs/toolkit";
export const errorSlice = createSlice({
name: "error",
initialState: {
postError: [],
userError: []
},
reducers: {
setPostError: (state,action) => {
state.postError = action.payload;
state.postUser = [];
},
setUserError: (state,action) => {
state.postUser = action.payload;
state.userError = [];
},
}
});
export const {setPostError} = errorSlice.actions;
export const {setUserError} = errorSlice.actions;
export default errorSlice.reducer;

@ -0,0 +1,21 @@
//import { combineReducers } from "redux";
import { configureStore } from "@reduxjs/toolkit";
import errorReducer from "./error.reducer";
import postReducer from "./post.reducer";
import userReducer from "./user.reducer";
import usersReducer from "./users.reducer";
/*export default combineReducers({
userReducer,
})*/
//import picturesReducer from "../feature/pictures.slice";
export default configureStore({
reducer: {
user: userReducer,
users: usersReducer,
post: postReducer,
error: errorReducer,
},
});

@ -0,0 +1,33 @@
import { createSlice } from "@reduxjs/toolkit";
export const postSlice = createSlice({
name: "post",
initialState: {
post : null,
},
reducers: {
setPostData: (state,action) => {
state.post = action.payload;
console.log(state.post)
},
setPostLikeData: (state,action) => {
console.log(...state.post);
if (state.post._id === action.payload.postId) {
return {
...state.post,
likers: [action.payload.userId, ...state.post.likers],
};
}
return state.post;
},
setPostUnLikeData: (state,action) => {
console.log(state);
console.log(action);
}
},
});
export const {setPostUnLikeData} = postSlice.actions;
export const {setPostLikeData} = postSlice.actions;
export const {setPostData} = postSlice.actions;
export default postSlice.reducer;

@ -0,0 +1,35 @@
import { createSlice } from "@reduxjs/toolkit";
export const userSlice = createSlice({
name: "user",
initialState: {
user: null,
},
reducers: {
setUserData: (state,action) => {
state.user = action.payload;
},
setUserDataImg: (state,action) => {
state.user = {...state, picture: action.payload};
},
setUserToFollowData: (state,action) => {
state.user = {...state,
following: [action.payload.idToFollow, ...state.following],}
},
setUserToUnFollowData: (state,action) => {
state.user = {...state,
following: state.following.filter(
(id) => id !== action.payload.idToUnfollow
),};
},
},
});
export const { setUserToFollowData} = userSlice.actions;
export const {setUserToUnFollowData} = userSlice.actions;
export const {setUserData} = userSlice.actions;
export const {setUserDataImg} = userSlice.actions;
export default userSlice.reducer;

@ -0,0 +1,16 @@
import { createSlice } from "@reduxjs/toolkit";
export const usersSlice = createSlice({
name: "users",
initialState: {
users: null,
},
reducers: {
setUsersData: (state,action) => {
state.users = action.payload;
},
},
});
export const {setUsersData} = usersSlice.actions;
export default usersSlice.reducer;

@ -1,10 +1,114 @@
.ajoutLien{ .button-add-link{
position: absolute; border: solid black 2px;
top: 100px; background-color: beige;
right: 50px; border-radius: 10px;
width: 140px;
height: 50px;
text-align: center;
} }
.bouttonAjoutLien{ .popup-profil-container {
height: 100px; z-index: 100;
width: 100px; width: 100%;
} top: 0;
left: 0;
height: 100%;
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;
h3 {
min-width: 200px;
}
@keyframes modal {
to {
transform: scale(1) translate(-50%);
}
}
.cross {
position: absolute;
top: 25px;
right: 25px;
transition: 0.1s;
cursor: pointer;
&:hover {
transform: scale(1.07);
}
}
ul {
margin: 20px 0 0;
max-height: 500px;
overflow-y: scroll;
overflow-x: hidden;
&::-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;
grid-template-columns: 64px 1fr 114px;
align-items: center;
margin: 10px 0;
img {
height: 50px;
width: 50px;
border-radius: 20px;
object-fit: cover;
box-shadow: 0 0 2px rgba(51, 51, 51, 0.376);
}
h4 {
text-align: left;
min-width: 210px;
}
.follow-handler {
text-align: left;
button {
background: $color-4;
border-radius: 20px;
margin-right: 6px;
&:hover {
color: $color-3;
transform: translateX(2px);
}
}
}
}
}
}
}

@ -1,142 +1,157 @@
:root {
header { --navbar-background-color: #f2f2f2;
height: 50px; --navbar-item-hovered-color:white;
background-color: $color-2; --navbar-separator-color:#ececec;
top: 0; --navbar-icon-color:#646c79;
left: 0; --navbar-text-color:black;
right: 0; --navbar-transition-speed: .2s;
text-transform: uppercase; --primary-color:#7C4DFF;
color: #b9b9b9; --navbar-logo-background-color:#e2dfe4;
position: fixed;
} }
nav{ html, body {
margin:0;
font-family: 'Source Sans Pro';
font-size:16px;
}
main {
padding: 1rem 4rem;
margin-left: 5rem;
display: flex; display: flex;
justify-content: center;
flex-direction: row;
}
.postInMain{
width: 80%;
}
.RightBar{
width: 20%;
height: 100px;
}
.navbar {
width:5rem;
position:fixed;
top:0px;
left:0px;
bottom:0px;
background:var(--navbar-background-color);
box-shadow: rgba(12,43, 30, 0.2) 0 4px 14px;
transition: width var(--navbar-transition-speed) ease;
}
.navbar:hover {
width:15rem;
}
.navbar-menu {
list-style: none;
padding:0;
margin:0;
display:flex;
flex-direction: column;
align-items: center; align-items: center;
justify-content: space-between; height:100%;
} }
.logo{ .navbar-item {
//margin-right: 250px; width: 100%;
border-bottom:solid 1px var(--navbar-separator-color);
transition: background-color var(--navbar-transition-speed);
} }
.navbar-item:hover {
background-color:var(--navbar-item-hovered-color);
}
.navbar-item:last-child {
margin-top:auto;
}
.partie-droit-nav,.partie-gauche-nav{ .navbar-link {
width: 20%; display:flex;
align-items: center;
justify-content: flex-start;
height:5rem;
width:100%;
text-decoration: none;
} }
.navbar-icon {
text-align: center;
font-size: 1.5rem;
min-width: 2rem;
margin: 0 1.5rem;
color:var(--navbar-icon-color);
transition:var(--navbar-transition-speed);
}
.svg-home{ .navbar-item:hover .navbar-icon {
height: 45px; color:var(--primary-color);
width: 45px;
} }
.svg-param{ .navbar-title {
height: 42px; color:var(--navbar-text-color);
width: 42px;
} }
.navbar:not(:hover) .navbar-title {
display:none;
}
.logo {
background:var(--navbar-logo-background-color);
}
.ul-navBar{ .logo .navbar-title {
display: flex; font-size:1.5rem;
li{ font-weight:bold;
list-style-type: none; margin-left:1.5rem;
padding-left: 1rem; }
align-self: center;
}
.nav-active-menu { .navbar:hover .logo .navbar-icon {
padding-top: 50px; transform:rotate(180deg);
} }
.nav-active-tendances-decouvrir { /*
padding-bottom: 0.75rem; ** RESPONSIVE
} */
.nav-active { @media only screen and (max-width:1024px) {
position: relative; .navbar {
top:auto;
&::after { width:100%;
content: ""; bottom:0px;
height: 4px;
background: violet;
position: absolute;
border-radius: 10px;
bottom: 0px;
left: 50%;
transform: translateX(-50%);
-webkit-animation: anim 0.3s ease forwards;
animation: anim 0.6s ease forwards;
@-webkit-keyframes anim {
to {
width: 100%;
}
}
@keyframes anim {
to {
width: 100%;
}
}
}
} }
}
.img-profile{ .navbar:hover {
height: 35px; width:100%;
width: 35px; }
border-radius: 20px;
}
.b{ .navbar-menu {
text-decoration: none; flex-direction: row;
cursor: pointer; }
}
.n{ .logo {
height: 0.95rem; display:none;
width: 0.95rem; }
padding-top: 0.15rem;
overflow: hidden;
fill: #b9b9b9;
}
main {
margin-left:0;
margin-bottom:5rem;
}
.more .menu-deroulant { .navbar:hover .navbar-title {
font-size: 20px; display:none;
outline: none; }
color: white;
background-color: inherit;
font-family: inherit;
margin-left: 60px;
}
.more-menu { .navbar-icon {
display: none; min-width:auto;
position: absolute; margin:0;
background-color: #f9f9f9; }
min-width: 200px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.more-menu .element-menu-deroulant {
float: none;
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
}
.dropdown-menu .element-menu-deroulant:hover { .navbar-link {
background-color: #cccccc; justify-content: center;
color: black; }
}
.more:hover .more-menu {
display: block;
} }

@ -2,15 +2,25 @@
background: white; background: white;
border: 2px solid grey; border: 2px solid grey;
border-radius:5px; border-radius:5px;
width: 40%; width: 70%;
margin-left: auto; margin-bottom: 20px;
margin-right: auto;
} }
#postContenu{
padding: 15px;
}
#hautPoste{ #hautPoste{
display: flex; display: flex;
align-items:center; align-items:center;
justify-content: space-between; justify-content: space-between;
margin-right: 15px; }
.conteneur_postes{
text-decoration: none;
list-style-type: none;
display: flex;
justify-content: center;
} }
#cadreInfoPoste{ #cadreInfoPoste{
@ -18,7 +28,7 @@
align-items:center; align-items:center;
} }
#PhotoProfile{ #PhotoProfile{
margin: 10px 15px 0px 20px; margin: 0px 15px 0px 0px;
width: 40px; width: 40px;
height:40px; height:40px;
border-radius: 20px; border-radius: 20px;

@ -14,7 +14,7 @@
} }
#blocAbonnement div{ #blocAbonnement .bloc-aboonnements-abonner{
margin-left: 80px; margin-left: 80px;
margin-right: 80px; margin-right: 80px;
} }
@ -23,6 +23,10 @@
text-align: center; text-align: center;
} }
.affichage-date{
font-size: 15px;
}
.nombre{ .nombre{
color:black; color:black;
} }
@ -36,3 +40,108 @@
margin-top: 50px; margin-top: 50px;
} }
.popup-profil-container {
z-index: 100;
width: 100%;
top: 0;
left: 0;
height: 100%;
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;
h3 {
min-width: 200px;
}
@keyframes modal {
to {
transform: scale(1) translate(-50%);
}
}
.cross {
position: absolute;
top: 25px;
right: 25px;
transition: 0.1s;
cursor: pointer;
&:hover {
transform: scale(1.07);
}
}
ul {
margin: 20px 0 0;
max-height: 500px;
overflow-y: scroll;
overflow-x: hidden;
&::-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;
grid-template-columns: 64px 1fr 114px;
align-items: center;
margin: 10px 0;
img {
height: 50px;
width: 50px;
border-radius: 20px;
object-fit: cover;
box-shadow: 0 0 2px rgba(51, 51, 51, 0.376);
}
h4 {
text-align: left;
min-width: 210px;
}
.follow-handler {
text-align: left;
button {
background: $color-4;
border-radius: 20px;
margin-right: 6px;
&:hover {
color: $color-3;
transform: translateX(2px);
}
}
}
}
}
}
}

@ -0,0 +1,8 @@
.ligneVertical{
border-right: thick solid #000;
height:85%;
}
.ligneHorizontal{
border-top: thick solid #000;
width: 78%;
}

@ -16,7 +16,7 @@ module.exports.readPost = (req, res) => {
module.exports.createPost = async (req, res) => { module.exports.createPost = async (req, res) => {
const newPost = new postModel({ const newPost = new postModel({
postedId: req.body.posterId, postedId: req.body.postedId,
message: req.body.message, message: req.body.message,
lien: req.body.lien, lien: req.body.lien,
likers: [], likers: [],
@ -70,20 +70,24 @@ module.exports.likePost = async (req, res) => {
{ {
$addToSet: { likers: req.body.id }, $addToSet: { likers: req.body.id },
}, },
{ new: true }) { new: true },
.then((data) => res.send(data)) (err, docs) => {
.catch((err) => res.status(500).send({ message: err })); if (err) return res.status(200).send(err);
}
);
await UserModel.findByIdAndUpdate( await UserModel.findByIdAndUpdate(
req.body.id, req.body.id,
{ {
$addToSet: { likes: req.params.id }, $addToSet: { likes: req.params.id },
}, },
{ new: true }) { new: true },
.then((data) => res.send(data)) (err, docs) => {
.catch((err) => res.status(500).send({ message: err })); if (!err) return res.send(docs);
else return res.status(200).send(err);
}
);
} catch (err) { } catch (err) {
return res.status(400).send(err); return res.status(200).send(err);
} }
}; };
@ -97,18 +101,22 @@ module.exports.unlikePost = async (req, res) => {
{ {
$pull: { likers: req.body.id }, $pull: { likers: req.body.id },
}, },
{ new: true }) { new: true },
.then((data) => res.send(data)) (err, docs) => {
.catch((err) => res.status(500).send({ message: err })); if (err) return res.status(400).send(err);
}
);
await UserModel.findByIdAndUpdate( await UserModel.findByIdAndUpdate(
req.body.id, req.body.id,
{ {
$pull: { likes: req.params.id }, $pull: { likes: req.params.id },
}, },
{ new: true }) { new: true },
.then((data) => res.send(data)) (err, docs) => {
.catch((err) => res.status(500).send({ message: err })); if (!err) return res.send(docs);
else return res.status(400).send(err);
}
);
} catch (err) { } catch (err) {
return res.status(400).send(err); return res.status(400).send(err);
} }

@ -59,22 +59,27 @@ module.exports.follow = async (req, res) => {
try { try {
// add to the follower list // add to the follower list
await UserModel.findByIdAndUpdate( await UserModel.findByIdAndUpdate(
req.params.id, req.params.id,
{ $addToSet: { following: req.body.idToFollow } }, { $addToSet: { following: req.body.idToFollow }, },
{ new: true, upsert: true } { new: true , upsert: true },
.then((data) => res.send(data)) (err, docs) => {
.catch((err) => res.status(500).send({ message: err }))), if (!err) return res.send(docs);
else return res.status(200).send(err);
}
)
// ajouter à la liste des followers // ajouter à la liste des followers
await UserModel.findByIdAndUpdate( await UserModel.findByIdAndUpdate(
req.body.idToFollow, req.body.idToFollow,
{ $addToSet: { followers: req.params.id } }, { $addToSet: { followers: req.params.id }, },
{ new: true, upsert: true } { new: true , upsert: true},
.then((data) => res.send(data)) (err, docs) => {
.catch((err) => res.status(500).send({ message: err }))) if (!err) return res.send(docs);
else return res.status(200).send(err);
}
);
} catch (err) { } catch (err) {
return res.status(500).json({ message: err }); return res.status(400).send(err);
} }
}; };
@ -88,19 +93,24 @@ module.exports.unfollow = async (req, res) => {
try { try {
await userModel.findByIdAndUpdate( await userModel.findByIdAndUpdate(
req.params.id, req.params.id,
{ $pull: { following: req.body.idToUnfollow } }, { $pull: { following: req.body.idToUnfollow ,} },
{ new: true, upsert: true } { new: true , upsert: true },
.then((data) => res.send(data)) (err, docs) => {
.catch((err) => res.status(500).send({ message: err }))), if (err) return res.status(400).send(err);
}
);
// Retirer de la liste des followers // Retirer de la liste des followers
await userModel.findByIdAndUpdate( await userModel.findByIdAndUpdate(
req.body.idToUnfollow, req.body.idToUnfollow,
{ $pull: { followers: req.params.id } }, { $pull: { followers: req.params.id } },
{ new: true, upsert: true } { new: true , upsert: true},
.then((data) => res.send(data)) (err, docs) => {
.catch((err) => res.status(500).send({ message: err }))) if (!err) return res.send(docs);
else return res.status(400).send(err);
}
);
} catch (err) { } catch (err) {
return res.status(500).json({ message: err }); return res.status(401).send(err);
} }
} }

@ -17,7 +17,7 @@ const app = express();
const corsOptions = { const corsOptions = {
origin: process.env.CLIENT_URL, origin: process.env.CLIENT_URL,
credentials: true, credentials: true,
'allowedHeaders': ['sessionId', 'Content-Type'], 'allowedHeaders': ['sessionId', 'Content-Type','Authorization'],
'exposedHeaders': ['sessionId'], 'exposedHeaders': ['sessionId'],
'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE', 'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'preflightContinue': false 'preflightContinue': false

360
package-lock.json generated

@ -0,0 +1,360 @@
{
"name": "Favor",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"multer": "^1.4.5-lts.1"
}
},
"node_modules/append-field": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"dependencies": {
"streamsearch": "^1.1.0"
},
"engines": {
"node": ">=10.16.0"
}
},
"node_modules/concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"engines": [
"node >= 0.8"
],
"dependencies": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimist": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"dependencies": {
"minimist": "^1.2.6"
},
"bin": {
"mkdirp": "bin/cmd.js"
}
},
"node_modules/multer": {
"version": "1.4.5-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
"dependencies": {
"append-field": "^1.0.0",
"busboy": "^1.0.0",
"concat-stream": "^1.5.2",
"mkdirp": "^0.5.4",
"object-assign": "^4.1.1",
"type-is": "^1.6.4",
"xtend": "^4.0.0"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"node_modules/readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"dependencies": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
},
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"engines": {
"node": ">=0.4"
}
}
},
"dependencies": {
"append-field": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz",
"integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw=="
},
"buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
"busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
"integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
"requires": {
"streamsearch": "^1.1.0"
}
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"minimist": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g=="
},
"mkdirp": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
"requires": {
"minimist": "^1.2.6"
}
},
"multer": {
"version": "1.4.5-lts.1",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz",
"integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==",
"requires": {
"append-field": "^1.0.0",
"busboy": "^1.0.0",
"concat-stream": "^1.5.2",
"mkdirp": "^0.5.4",
"object-assign": "^4.1.1",
"type-is": "^1.6.4",
"xtend": "^4.0.0"
}
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"streamsearch": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
"integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"type-is": {
"version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"requires": {
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
}
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}
}
}

@ -0,0 +1,5 @@
{
"dependencies": {
"multer": "^1.4.5-lts.1"
}
}
Loading…
Cancel
Save