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'> <div className='ajoutLien'>
<button className="bouttonAjoutLien" id="display" type='bouton' onClick={handleModals}> {uid === null &&
<button className="bouttonAjoutLien" id="display" type='bouton'>
Se connecter
</button>
}
{uid !== null &&
<button className='button-add-link' onClick={() => setDisplayAdd(true)} >
Poster un lien Poster un lien
</button> </button>
}
</div> </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>

@ -16,7 +16,6 @@ const PolitiqueDeConfidentialite =()=>{
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,17 +1,65 @@
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"){
@ -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">
<li>
<NavLink to="/Discover" className={((nav) => (nav.isActive ? "nav-active b nav-active-tendances-decouvrir" : "b"))}>
<span>Découvrir</span>
</NavLink> </NavLink>
</li> </li>
<li className="navbar-item">
<li> <NavLink to="/Home" className="navbar-link">
<NavLink to="/Home" className={((nav) => (nav.isActive ? "nav-active b nav-active-menu" : "b"))}> <i className="fas fa-home navbar-icon"></i>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" className="svg-home"> <span className="navbar-title">Home</span>
<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>
</NavLink> </NavLink>
</li> </li>
<li className="navbar-item">
<NavLink to="/Discover" className="navbar-link">
<li> <i className="fas fa-bullseye navbar-icon"></i>
<NavLink to="/Trends" className={((nav) => (nav.isActive ? "nav-active b nav-active-tendances-decouvrir" : "b"))}> <span className="navbar-title">Découvrir</span>
<span>Tendances</span>
</NavLink> </NavLink>
</li> </li>
</ul> <li className="navbar-item">
<ul className="partie-droit-nav ul-navBar"> <NavLink to="/Trends" className="navbar-link">
<li > <i className="fas fa-bell navbar-icon"></i>
<NavLink to="/Profil" className='b'> <span className="navbar-title">Notifications</span>
{ (userData==null) ? (<span></span>):(<span>{userData.pseudo}</span>)}
</NavLink> </NavLink>
</li> </li>
<li className="navbar-item">
<li> <NavLink to="/Profil" className="navbar-link">
<NavLink to="/Profil" className='b'> <i className="fas fa-user navbar-icon"></i>
<img src={PP} alt='Logo' className="img-profile"/> <span className="navbar-title">Me</span>
</NavLink> </NavLink>
</li> </li>
<li className="navbar-item">
<li> <a onClick={() => setDisplayAdd(true)} className="navbar-link">
<div className='b more'> <i className="fas fa-cog navbar-icon"></i>
<div className="menu-deroulant"> <span className="navbar-title">Paramètre</span>
<svg xmlns="http://www.w3.org/2000/svg" className="svg-param" viewBox="0 0 256 256"> </a>
<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"/> </li>
</svg> <li className="navbar-item">
</div> <a onClick={logout} className="navbar-link">
<div className="more-menu"> <i className="fas fa-sign-out-alt navbar-icon"></i>
<NavLink className='element-menu-deroulant' to="/Configuration">Configurations</NavLink> <span className="navbar-title">Déconnexion</span>
<NavLink className='element-menu-deroulant'>Élement 2</NavLink> </a>
<NavLink className='element-menu-deroulant' onClick={logout}>Élement 3</NavLink>
</div>
</div>
</li> </li>
</ul> </ul>
</nav> </nav>
</header> // <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>
// <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">
// <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>
// </NavLink>
// </li>
// <li>
// <NavLink to="/Trends" className={((nav) => (nav.isActive ? "nav-active b nav-active-tendances-decouvrir" : "b"))}>
// <span>Tendances</span>
// </NavLink>
// </li>
// </ul>
// <ul className="partie-droit-nav ul-navBar">
// <li >
// <NavLink to="/Profil" className='b'>
// { (userData==null) ? (<span></span>):(<span>{userData.pseudo}</span>)}
// </NavLink>
// </li>
// <li>
// <NavLink to="/Profil" className='b'>
// <img src={PP} alt='Logo' className="img-profile"/>
// </NavLink>
// </li>
// <li>
// <div className='b more'>
// <div className="menu-deroulant">
// <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"/>
// </svg>
// </div>
// <div className="more-menu">
// <NavLink className='element-menu-deroulant' to="/Configuration">Configurations</NavLink>
// <a onClick={() => setDisplayAdd(true)} className='element-menu-deroulant'>Élement 2</a>
// <NavLink className='element-menu-deroulant' onClick={logout}>Élement 3</NavLink>
// </div>
// </div>
// </li>
// </ul>
// </nav>
// </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 />
<main >
<div className='postInMain'>
<DisplayPosts/>
</div>
<div className="RightBar">
<AjoutLien/> <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 {
display: flex; margin:0;
align-items: center; font-family: 'Source Sans Pro';
justify-content: space-between; font-size:16px;
} }
main {
padding: 1rem 4rem;
margin-left: 5rem;
display: flex;
justify-content: center;
flex-direction: row;
.logo{
//margin-right: 250px;
} }
.postInMain{
width: 80%;
}
.partie-droit-nav,.partie-gauche-nav{ .RightBar{
width: 20%; 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;
}
.svg-home{ .navbar:hover {
height: 45px; width:15rem;
width: 45px;
} }
.svg-param{ .navbar-menu {
height: 42px; list-style: none;
width: 42px; padding:0;
margin:0;
display:flex;
flex-direction: column;
align-items: center;
height:100%;
} }
.navbar-item {
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);
}
.ul-navBar{ .navbar-item:last-child {
display: flex; margin-top:auto;
li{ }
list-style-type: none;
padding-left: 1rem;
align-self: center;
}
.nav-active-menu { .navbar-link {
padding-top: 50px; display:flex;
} align-items: center;
justify-content: flex-start;
height:5rem;
width:100%;
text-decoration: none;
}
.nav-active-tendances-decouvrir { .navbar-icon {
padding-bottom: 0.75rem; text-align: center;
} font-size: 1.5rem;
min-width: 2rem;
margin: 0 1.5rem;
color:var(--navbar-icon-color);
transition:var(--navbar-transition-speed);
}
.nav-active { .navbar-item:hover .navbar-icon {
position: relative; color:var(--primary-color);
&::after {
content: "";
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-title {
height: 35px; color:var(--navbar-text-color);
width: 35px;
border-radius: 20px;
} }
.b{ .navbar:not(:hover) .navbar-title {
text-decoration: none; display:none;
cursor: pointer;
} }
.n{ .logo {
height: 0.95rem; background:var(--navbar-logo-background-color);
width: 0.95rem;
padding-top: 0.15rem;
overflow: hidden;
fill: #b9b9b9;
} }
.logo .navbar-title {
font-size:1.5rem;
font-weight:bold;
margin-left:1.5rem;
}
.more .menu-deroulant { .navbar:hover .logo .navbar-icon {
font-size: 20px; transform:rotate(180deg);
outline: none;
color: white;
background-color: inherit;
font-family: inherit;
margin-left: 60px;
} }
.more-menu { /*
display: none; ** RESPONSIVE
position: absolute; */
background-color: #f9f9f9;
min-width: 200px; @media only screen and (max-width:1024px) {
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); .navbar {
z-index: 1; top:auto;
width:100%;
bottom:0px;
} }
.more-menu .element-menu-deroulant { .navbar:hover {
float: none; width:100%;
color: black; }
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
}
.dropdown-menu .element-menu-deroulant:hover { .navbar-menu {
background-color: #cccccc; flex-direction: row;
color: black; }
}
.logo {
display:none;
}
main {
margin-left:0;
margin-bottom:5rem;
}
.more:hover .more-menu { .navbar:hover .navbar-title {
display: block; display:none;
}
.navbar-icon {
min-width:auto;
margin:0;
}
.navbar-link {
justify-content: center;
}
} }

@ -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);
} }

@ -61,20 +61,25 @@ module.exports.follow = async (req, res) => {
// 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