frontend: Édition profil + corrections backend
This commit is contained in:
parent
3ed605af1b
commit
5d048f3010
@ -9,7 +9,7 @@ function deleteFilesNameStartWith(pattern, dirPath = __dirname) {
|
|||||||
// Iterate through the found file names
|
// Iterate through the found file names
|
||||||
for (const name of fileNames) {
|
for (const name of fileNames) {
|
||||||
// If file name matches the pattern
|
// If file name matches the pattern
|
||||||
if (name.startsWith(pattern)) {
|
if (name.startsWith(pattern) && name !== 'default.png') {
|
||||||
console.log(name)
|
console.log(name)
|
||||||
fs.unlinkSync(path.join(dirPath, name));
|
fs.unlinkSync(path.join(dirPath, name));
|
||||||
}
|
}
|
||||||
|
@ -19,14 +19,27 @@ const deleteFilesNameStartWith = require('../assets/utils/deleteFilesNameS
|
|||||||
async function handleEditUser(res, { name, email, biography, isPublicEmail }, userId, logoName) {
|
async function handleEditUser(res, { name, email, biography, isPublicEmail }, userId, logoName) {
|
||||||
const user = await Users.findOne({ where: { id: userId } });
|
const user = await Users.findOne({ where: { id: userId } });
|
||||||
user.name = name;
|
user.name = name;
|
||||||
user.email = email;
|
if (user.email !== email) {
|
||||||
user.biography = biography;
|
const tempToken = uuid.v4();
|
||||||
|
user.email = email;
|
||||||
|
user.isConfirmed = false;
|
||||||
|
user.tempToken = tempToken;
|
||||||
|
await transporter.sendMail({
|
||||||
|
from: `"FunctionProject" <${EMAIL_INFO.auth.user}>`,
|
||||||
|
to: email,
|
||||||
|
subject: "FunctionProject - Confirmer l'email",
|
||||||
|
html: emailTemplate("Veuillez confirmer l'email", "Oui, je confirme.", `${HOST}/users/confirm-email/${tempToken}`, "Si vous avez reçu ce message par erreur, il suffit de le supprimer. Votre email ne serez pas confirmé si vous ne cliquez pas sur le lien de confirmation ci-dessus.")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (biography != undefined) {
|
||||||
|
user.biography = biography;
|
||||||
|
}
|
||||||
user.isPublicEmail = isPublicEmail;
|
user.isPublicEmail = isPublicEmail;
|
||||||
if (logoName != undefined) {
|
if (logoName != undefined) {
|
||||||
user.logo = `/images/users/${logoName}`;
|
user.logo = `/images/users/${logoName}`;
|
||||||
}
|
}
|
||||||
await user.save();
|
await user.save();
|
||||||
return res.status(200).json({ message: "Le profil a bien été modifié!" });
|
return res.status(200).json({ id: user.id, name: user.name, email: user.email, biography: user.biography, logo: user.logo, isPublicEmail: user.isPublicEmail, isAdmin: user.isAdmin, createdAt: user.createdAt });
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.putUser = (req, res, next) => {
|
exports.putUser = (req, res, next) => {
|
||||||
@ -115,7 +128,7 @@ exports.login = async (req, res, next) => {
|
|||||||
}
|
}
|
||||||
const token = jwt.sign({
|
const token = jwt.sign({
|
||||||
email: user.email, userId: user.id
|
email: user.email, userId: user.id
|
||||||
}, JWT_SECRET, { expiresIn: '3h' });
|
}, JWT_SECRET, { expiresIn: '6h' });
|
||||||
return res.status(200).json({ token, id: user.id, name: user.name, email: user.email, biography: user.biography, logo: user.logo, isPublicEmail: user.isPublicEmail, isAdmin: user.isAdmin, createdAt: user.createdAt });
|
return res.status(200).json({ token, id: user.id, name: user.name, email: user.email, biography: user.biography, logo: user.logo, isPublicEmail: user.isPublicEmail, isAdmin: user.isAdmin, createdAt: user.createdAt });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@ -198,7 +211,7 @@ exports.getUserInfo = async (req, res, next) => {
|
|||||||
const { name } = req.params;
|
const { name } = req.params;
|
||||||
try {
|
try {
|
||||||
const user = await Users.findOne({
|
const user = await Users.findOne({
|
||||||
where: { name },
|
where: { name, isConfirmed: true },
|
||||||
attributes: {
|
attributes: {
|
||||||
exclude: ["updatedAt", "isAdmin", "isConfirmed", "password", "tempToken", "tempExpirationToken"]
|
exclude: ["updatedAt", "isAdmin", "isConfirmed", "password", "tempToken", "tempExpirationToken"]
|
||||||
},
|
},
|
||||||
@ -232,6 +245,7 @@ exports.getUserInfo = async (req, res, next) => {
|
|||||||
const userObject = {
|
const userObject = {
|
||||||
// Si Public Email
|
// Si Public Email
|
||||||
... (user.isPublicEmail) && { email: user.email },
|
... (user.isPublicEmail) && { email: user.email },
|
||||||
|
isPublicEmail: user.isPublicEmail,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
biography: user.biography,
|
biography: user.biography,
|
||||||
logo: user.logo,
|
logo: user.logo,
|
||||||
|
9
website/components/Modal.js
Normal file
9
website/components/Modal.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const Modal = (props) => (
|
||||||
|
<div className="Modal container-fluid">
|
||||||
|
<div className="Modal__content">
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Modal;
|
@ -26,8 +26,7 @@ function UserContextProvider(props) {
|
|||||||
api.post('/users/login', { email, password })
|
api.post('/users/login', { email, password })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const user = response.data;
|
const user = response.data;
|
||||||
cookies.set('user', user);
|
changeUserValue(user);
|
||||||
setUser(user);
|
|
||||||
setIsAuth(true);
|
setIsAuth(true);
|
||||||
setMessageLogin('<p class="form-success"><b>Succès:</b> Connexion réussi!</p>');
|
setMessageLogin('<p class="form-success"><b>Succès:</b> Connexion réussi!</p>');
|
||||||
setLoginLoading(false);
|
setLoginLoading(false);
|
||||||
@ -46,8 +45,14 @@ function UserContextProvider(props) {
|
|||||||
setIsAuth(false);
|
setIsAuth(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changeUserValue = (user) => {
|
||||||
|
cookies.remove('user');
|
||||||
|
cookies.set('user', user);
|
||||||
|
setUser(user);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UserContext.Provider value={{ user, loginUser, logoutUser, loginLoading, messageLogin, isAuth }}>
|
<UserContext.Provider value={{ user, loginUser, logoutUser, loginLoading, messageLogin, isAuth, changeUserValue }}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</UserContext.Provider>
|
</UserContext.Provider>
|
||||||
);
|
);
|
||||||
|
29
website/package-lock.json
generated
29
website/package-lock.json
generated
@ -1395,6 +1395,35 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
|
||||||
"integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw=="
|
"integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw=="
|
||||||
},
|
},
|
||||||
|
"@fortawesome/fontawesome-common-types": {
|
||||||
|
"version": "0.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.28.tgz",
|
||||||
|
"integrity": "sha512-gtis2/5yLdfI6n0ia0jH7NJs5i/Z/8M/ZbQL6jXQhCthEOe5Cr5NcQPhgTvFxNOtURE03/ZqUcEskdn2M+QaBg=="
|
||||||
|
},
|
||||||
|
"@fortawesome/fontawesome-svg-core": {
|
||||||
|
"version": "1.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.28.tgz",
|
||||||
|
"integrity": "sha512-4LeaNHWvrneoU0i8b5RTOJHKx7E+y7jYejplR7uSVB34+mp3Veg7cbKk7NBCLiI4TyoWS1wh9ZdoyLJR8wSAdg==",
|
||||||
|
"requires": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "^0.2.28"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@fortawesome/free-solid-svg-icons": {
|
||||||
|
"version": "5.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.13.0.tgz",
|
||||||
|
"integrity": "sha512-IHUgDJdomv6YtG4p3zl1B5wWf9ffinHIvebqQOmV3U+3SLw4fC+LUCCgwfETkbTtjy5/Qws2VoVf6z/ETQpFpg==",
|
||||||
|
"requires": {
|
||||||
|
"@fortawesome/fontawesome-common-types": "^0.2.28"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@fortawesome/react-fontawesome": {
|
||||||
|
"version": "0.1.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.9.tgz",
|
||||||
|
"integrity": "sha512-49V3WNysLZU5fZ3sqSuys4nGRytsrxJktbv3vuaXkEoxv22C6T7TEG0TW6+nqVjMnkfCQd5xOnmJoZHMF78tOw==",
|
||||||
|
"requires": {
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@next/polyfill-nomodule": {
|
"@next/polyfill-nomodule": {
|
||||||
"version": "9.3.2",
|
"version": "9.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/@next/polyfill-nomodule/-/polyfill-nomodule-9.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/@next/polyfill-nomodule/-/polyfill-nomodule-9.3.2.tgz",
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
"start": "cross-env NODE_ENV=production node server"
|
"start": "cross-env NODE_ENV=production node server"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-svg-core": "^1.2.28",
|
||||||
|
"@fortawesome/free-solid-svg-icons": "^5.13.0",
|
||||||
|
"@fortawesome/react-fontawesome": "^0.1.9",
|
||||||
"@zeit/next-css": "^1.0.1",
|
"@zeit/next-css": "^1.0.1",
|
||||||
"axios": "^0.19.2",
|
"axios": "^0.19.2",
|
||||||
"date-and-time": "^0.13.1",
|
"date-and-time": "^0.13.1",
|
||||||
|
@ -13,7 +13,7 @@ const Login = () => {
|
|||||||
const [inputState, setInputState] = useState({});
|
const [inputState, setInputState] = useState({});
|
||||||
const { loginUser, messageLogin, loginLoading } = useContext(UserContext);
|
const { loginUser, messageLogin, loginLoading } = useContext(UserContext);
|
||||||
|
|
||||||
const handleChange = () => {
|
const handleChange = (event) => {
|
||||||
const inputStateNew = { ...inputState };
|
const inputStateNew = { ...inputState };
|
||||||
inputStateNew[event.target.name] = event.target.value;
|
inputStateNew[event.target.name] = event.target.value;
|
||||||
setInputState(inputStateNew);
|
setInputState(inputStateNew);
|
||||||
@ -55,7 +55,8 @@ const Login = () => {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div className="form-result text-center">
|
<div className="form-result text-center">
|
||||||
{(router.query.isConfirmed !== undefined) && <p className="form-success"><b>Succès:</b> Votre compte a bien été confirmé, vous pouvez maintenant vous connectez!</p>}
|
{(router.query.isConfirmed !== undefined && messageLogin === "") && <p className="form-success"><b>Succès:</b> Votre compte a bien été confirmé, vous pouvez maintenant vous connectez!</p>}
|
||||||
|
{(router.query.isSuccessEdit !== undefined && messageLogin === "") && <p className="form-success"><b>Succès:</b> Votre profil a bien été modifié, vous pouvez maintenant vous connectez!</p>}
|
||||||
{
|
{
|
||||||
(loginLoading) ?
|
(loginLoading) ?
|
||||||
<Loader />
|
<Loader />
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Fragment } from 'react';
|
import { Fragment, useContext, useState } from 'react';
|
||||||
|
import { UserContext } from '../../contexts/UserContext';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { faPen, faTimes } from '@fortawesome/free-solid-svg-icons';
|
||||||
import date from 'date-and-time';
|
import date from 'date-and-time';
|
||||||
import HeadTag from '../../components/HeadTag';
|
import HeadTag from '../../components/HeadTag';
|
||||||
import FunctionCard from '../../components/FunctionCard/FunctionCard';
|
import FunctionCard from '../../components/FunctionCard/FunctionCard';
|
||||||
|
import Modal from '../../components/Modal';
|
||||||
import redirect from '../../utils/redirect';
|
import redirect from '../../utils/redirect';
|
||||||
|
import htmlParser from 'html-react-parser';
|
||||||
|
import Loader from '../../components/Loader';
|
||||||
import api from '../../utils/api';
|
import api from '../../utils/api';
|
||||||
import { API_URL } from '../../utils/config';
|
import { API_URL } from '../../utils/config';
|
||||||
import '../../public/css/pages/profile.css';
|
import '../../public/css/pages/profile.css';
|
||||||
@ -14,25 +20,142 @@ const Profile = (props) => {
|
|||||||
const createdAt = new Date(props.createdAt);
|
const createdAt = new Date(props.createdAt);
|
||||||
const publicationDate = `${('0'+createdAt.getDate()).slice(-2)}/${('0'+(createdAt.getMonth()+1)).slice(-2)}/${createdAt.getFullYear()}`;
|
const publicationDate = `${('0'+createdAt.getDate()).slice(-2)}/${('0'+(createdAt.getMonth()+1)).slice(-2)}/${createdAt.getFullYear()}`;
|
||||||
|
|
||||||
|
const { isAuth, user, logoutUser } = useContext(UserContext);
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
let defaultInputState = {};
|
||||||
|
if (isAuth) {
|
||||||
|
defaultInputState = { name: user.name, email: user.email, biography: user.biography, isPublicEmail: user.isPublicEmail };
|
||||||
|
}
|
||||||
|
const [inputState, setInputState] = useState(defaultInputState);
|
||||||
|
|
||||||
|
const [message, setMessage] = useState("");
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const toggleModal = () => setIsOpen(!isOpen);
|
||||||
|
|
||||||
|
const handleChange = (event, isTypeCheck = false) => {
|
||||||
|
const inputStateNew = { ...inputState };
|
||||||
|
inputStateNew[event.target.name] = (event.target.files != undefined) ? event.target.files[0] : (isTypeCheck) ? event.target.checked : event.target.value;
|
||||||
|
setInputState(inputStateNew);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const token = user.token;
|
||||||
|
if (isAuth && token != undefined) {
|
||||||
|
setIsLoading(true);
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('name', inputState.name);
|
||||||
|
formData.append('email', inputState.email);
|
||||||
|
formData.append('biography', inputState.biography);
|
||||||
|
formData.append('isPublicEmail', inputState.isPublicEmail);
|
||||||
|
formData.append('logo', inputState.logo);
|
||||||
|
|
||||||
|
api.put('/users/', formData, { headers: { 'Authorization': user.token } })
|
||||||
|
.then(() => {
|
||||||
|
setIsLoading(false);
|
||||||
|
logoutUser();
|
||||||
|
redirect({}, '/login?isSuccessEdit=true');
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
setMessage(`<p class="form-error"><b>Erreur:</b> ${error.response.data.message}</p>`);
|
||||||
|
setIsLoading(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<HeadTag title={`${props.name} - FunctionProject`} description={`Profil utilisateur de ${props.name}. ${(props.biography != undefined) ? props.biography : ""}`} />
|
<HeadTag title={`${props.name} - FunctionProject`} description={`Profil utilisateur de ${props.name}. ${(props.biography != undefined) ? props.biography : ""}`} />
|
||||||
|
|
||||||
<div className="container-fluid Profile__container">
|
{/* Édition du profil */}
|
||||||
|
{(isOpen) &&
|
||||||
|
<Modal toggleModal={toggleModal}>
|
||||||
|
<div className="container-fluid Profile__container">
|
||||||
|
<div className="row Profile__row">
|
||||||
|
<div className="col-24">
|
||||||
|
<div className="Profile__Modal-top-container row">
|
||||||
|
<div className="col-24">
|
||||||
|
<span onClick={toggleModal} style={{ cursor: 'pointer', position: 'absolute', left: 0 }}>
|
||||||
|
<FontAwesomeIcon icon={faTimes} style={{ width: '1.5rem', color: 'red' }} />
|
||||||
|
</span>
|
||||||
|
<h2 className="text-center">Éditer le profil</h2>
|
||||||
|
<p className="text-center"><em>(Vous devrez vous reconnecter après la sauvegarde) <br/> Si vous changez votre adresse email, vous devrez la confirmer (vérifier vos emails).</em></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-24">
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="form-group">
|
||||||
|
<label className="form-label" htmlFor="name">Nom :</label>
|
||||||
|
<input value={inputState.name} onChange={handleChange} type="text" name="name" id="name" className="form-control" placeholder="Divlo" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label className="form-label" htmlFor="email">Email :</label>
|
||||||
|
<input value={inputState.email} onChange={handleChange} type="email" name="email" id="email" className="form-control" placeholder="email@gmail.com" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group custom-control custom-switch">
|
||||||
|
<input onChange={(event) => handleChange(event, true)} type="checkbox" name="isPublicEmail" checked={inputState.isPublicEmail} className="custom-control-input" id="isPublicEmail" />
|
||||||
|
<label className="custom-control-label" htmlFor="isPublicEmail">Email Public</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label className="form-label" htmlFor="biography">Biographie :</label>
|
||||||
|
<textarea style={{ height: 'auto' }} value={inputState.biography} onChange={handleChange} name="biography" id="biography" className="form-control" rows="5"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label className="form-label" htmlFor="logo">Logo <em>(400x400 recommandé)</em> :</label>
|
||||||
|
<br/>
|
||||||
|
<input onChange={handleChange} accept="image/jpeg,image/jpg,image/png,image/gif" type="file" name="logo" id="logo" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group text-center">
|
||||||
|
<button type="submit" className="btn btn-dark">Sauvegarder</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div className="form-result text-center">
|
||||||
|
{
|
||||||
|
(isLoading) ?
|
||||||
|
<Loader />
|
||||||
|
:
|
||||||
|
htmlParser(message)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className={`container-fluid Profile__container ${(isOpen) ? "d-none" : ""}`}>
|
||||||
<div className="row Profile__row">
|
<div className="row Profile__row">
|
||||||
<div className="col-20">
|
<div className="col-20">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<h1>Profil de <span className="important">{props.name}</span></h1>
|
<h1>Profil de <span className="important">{props.name}</span></h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="row justify-content-center">
|
<div className="row justify-content-center">
|
||||||
|
|
||||||
<div className="col-24 text-center">
|
<div className="col-24 text-center">
|
||||||
<img className="Profile__logo" src={API_URL + props.logo} alt={props.name} />
|
<img className="Profile__logo" src={API_URL + props.logo} alt={props.name} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-24 text-center">
|
<div className="col-24 text-center">
|
||||||
{(props.biography != undefined) && <p>{props.biography}</p>}
|
{(props.biography != undefined) && <p>{props.biography}</p>}
|
||||||
{(props.email != undefined) && <p><span className="important">Email :</span> {props.email}</p>}
|
{(props.email != undefined) && <p><span className="important">Email :</span> {props.email}</p>}
|
||||||
<p><span className="important">Date de création :</span> {publicationDate}</p>
|
<p><span className="important">Date de création :</span> {publicationDate}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{(isAuth && user.name === props.name) &&
|
||||||
|
<button onClick={toggleModal} style={{ marginBottom: '25px' }} className="btn btn-dark">
|
||||||
|
<FontAwesomeIcon icon={faPen} style={{cursor: 'pointer', width: '1rem'}} />
|
||||||
|
Éditez le profil
|
||||||
|
</button>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -59,13 +182,13 @@ const Profile = (props) => {
|
|||||||
<div className="col-24 text-center">
|
<div className="col-24 text-center">
|
||||||
<h2>Derniers <span className="important">commentaires :</span></h2>
|
<h2>Derniers <span className="important">commentaires :</span></h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-18 text-center">
|
<div className="col-24 text-center">
|
||||||
{props.commentsArray.map((comment) => (
|
{props.commentsArray.map((comment) => (
|
||||||
<div key={comment.id} className="row Profile__row Profile__comment">
|
<div key={comment.id} className="row Profile__row Profile__comment">
|
||||||
<div className="col-20">
|
<div className="col-20">
|
||||||
<p>
|
<p>
|
||||||
Posté sur la fonction
|
Posté sur la fonction
|
||||||
<Link href={(comment.function.type === 'form' || comment.function.type === 'article') ? "/functions/[slug]" : `/functions/${props.slug}`} as={`/functions/${comment.function.slug}`}>
|
<Link href={(comment.function.type === 'form' || comment.function.type === 'article') ? "/functions/[slug]" : `/functions/${comment.function.slug}`} as={`/functions/${comment.function.slug}`}>
|
||||||
<a>{comment.function.title}</a>
|
<a>{comment.function.title}</a>
|
||||||
</Link>
|
</Link>
|
||||||
le {date.format(new Date(comment.createdAt), 'DD/MM/YYYY à HH:mm', true)}
|
le {date.format(new Date(comment.createdAt), 'DD/MM/YYYY à HH:mm', true)}
|
||||||
|
@ -11,7 +11,7 @@ const Register = () => {
|
|||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleChange = () => {
|
const handleChange = (event) => {
|
||||||
const inputStateNew = { ...inputState };
|
const inputStateNew = { ...inputState };
|
||||||
inputStateNew[event.target.name] = event.target.value;
|
inputStateNew[event.target.name] = event.target.value;
|
||||||
setInputState(inputStateNew);
|
setInputState(inputStateNew);
|
||||||
|
@ -23,3 +23,69 @@
|
|||||||
.Profile__comment {
|
.Profile__comment {
|
||||||
margin: 0 0 50px 0;
|
margin: 0 0 50px 0;
|
||||||
}
|
}
|
||||||
|
.Profile__Modal-top-container {
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.custom-control {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.custom-control-input {
|
||||||
|
position: absolute;
|
||||||
|
z-index: -1;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.custom-control-label {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 0;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.custom-control-input:checked~.custom-control-label::before {
|
||||||
|
color: #fff;
|
||||||
|
border-color: #007bff;
|
||||||
|
background-color: #007bff;
|
||||||
|
}
|
||||||
|
.custom-switch .custom-control-label::before {
|
||||||
|
left: -2.25rem;
|
||||||
|
width: 1.75rem;
|
||||||
|
pointer-events: all;
|
||||||
|
border-radius: .5rem;
|
||||||
|
}
|
||||||
|
.custom-control-label::before {
|
||||||
|
position: absolute;
|
||||||
|
top: .25rem;
|
||||||
|
left: -1.5rem;
|
||||||
|
display: block;
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
pointer-events: none;
|
||||||
|
content: "";
|
||||||
|
background-color: #fff;
|
||||||
|
border: #adb5bd solid 1px;
|
||||||
|
}
|
||||||
|
.custom-switch .custom-control-input:checked~.custom-control-label::after {
|
||||||
|
background-color: #fff;
|
||||||
|
-webkit-transform: translateX(.75rem);
|
||||||
|
transform: translateX(.75rem);
|
||||||
|
}
|
||||||
|
.custom-switch .custom-control-label::after {
|
||||||
|
top: calc(.25rem + 2px);
|
||||||
|
left: calc(-2.25rem + 2px);
|
||||||
|
width: calc(1rem - 4px);
|
||||||
|
height: calc(1rem - 4px);
|
||||||
|
background-color: #adb5bd;
|
||||||
|
border-radius: .5rem;
|
||||||
|
transition: background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;
|
||||||
|
transition: transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
|
||||||
|
transition: transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,-webkit-transform .15s ease-in-out;
|
||||||
|
}
|
||||||
|
.custom-control-label::after {
|
||||||
|
position: absolute;
|
||||||
|
top: .25rem;
|
||||||
|
left: -1.5rem;
|
||||||
|
display: block;
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
content: "";
|
||||||
|
background: no-repeat 50%/50% 50%;
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
function redirect(ctx, path) {
|
function redirect(ctx, path) {
|
||||||
if (ctx.res) {
|
if (ctx.res != undefined) {
|
||||||
ctx.res.writeHead(302, { Location: path });
|
ctx.res.writeHead(302, { Location: path });
|
||||||
ctx.res.end();
|
ctx.res.end();
|
||||||
} else {
|
} else {
|
||||||
document.location.pathname = path;
|
document.location.href = path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user