refacto: devWeb - move css and js in files and import them in .jsp files

This commit is contained in:
kmitresse
2024-05-05 17:48:31 +02:00
parent 5596afea94
commit 8fcc732d0b
27 changed files with 481 additions and 531 deletions
@@ -15,7 +15,7 @@ import uppa.project.json.HttpResponse;
import uppa.project.json.HttpResponseCode;
public class ProfileBean {
private String id;
private String username;
private String oldEmail;
private String email;
private String oldPassword;
@@ -38,7 +38,7 @@ public class ProfileBean {
try {
userDAO= new Game_JPA_DAO_Factory().getDAOUser();
// Vérification de l'existence de l'utilisateur
user = userDAO.findById(Integer.parseInt(id));
user = (userDAO.findByField("username",username).length == 0 ? null : userDAO.findByField("username",username)[0]);
if (user == null) {
error = new HttpResponse(HttpResponseCode.UNAUTHORIZED, "Utilisateur non trouvé");
entityManager.getTransaction().rollback();
@@ -81,11 +81,11 @@ public class ProfileBean {
/**
*
* @param id l'identifiant de l'utilisateur
* @param username le pseudo de l'utilisateur
* @return l'entité
*/
public ProfileBean setId(String id) {
this.id = id;
public ProfileBean setUsername(String username) {
this.username = username;
return this;
}
@@ -67,7 +67,7 @@ public class ProfileServlet extends HttpServlet {
PrintWriter out = response.getWriter();
ProfileBean profileBean = new ProfileBean()
.setId(request.getParameter("id"))
.setUsername(request.getParameter("username"))
.setOldEmail(request.getParameter("oldEmail"))
.setEmail(request.getParameter("email"))
.setOldPassword(request.getParameter("oldPassword"))
@@ -4,14 +4,19 @@
<%@taglib prefix="form" tagdir="/WEB-INF/tags/forms" %>
<layout:form title="Mot de passe oublié">
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">Mot de passe oublié ?</h1>
<form:forgotten-password/>
<jsp:attribute name="script">
<script defer type="module" src="${pageContext.request.contextPath}/static/js/form/forgotten-password.js"></script>
</jsp:attribute>
<jsp:body>
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">Mot de passe oublié ?</h1>
<form:forgotten-password/>
</div>
</div>
</div>
</div>
</component:hero>
</layout:form>
</component:hero>
</jsp:body>
</layout:form>
@@ -4,17 +4,22 @@
<%@taglib prefix="form" tagdir="/WEB-INF/tags/forms" %>
<layout:form title="Connexion">
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">Se connecter</h1>
<form:login/>
<hr/>
<p class="content has-text-centered">Vous n'avez pas de compte ? <a href="${pageContext.request.contextPath}/register">S'inscrire</a>
</p>
<jsp:attribute name="script">
<script defer type="module" src="${pageContext.request.contextPath}/static/js/form/login.js"></script>
</jsp:attribute>
<jsp:body>
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">Se connecter</h1>
<form:login/>
<hr/>
<p class="content has-text-centered">Vous n'avez pas de compte ? <a href="${pageContext.request.contextPath}/register">S'inscrire</a>
</p>
</div>
</div>
</div>
</div>
</component:hero>
</layout:form>
</component:hero>
</jsp:body>
</layout:form>
@@ -4,20 +4,25 @@
<%@taglib prefix="form" tagdir="/WEB-INF/tags/forms" %>
<layout:form>
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">Nouvelle partie</h1>
<form:new-game>
<jsp:attribute name="back_button">
<div class="column">
<a class="button is-fullwidth" href="${pageContext.request.contextPath}/lobby">Revenir au menu</a>
</div>
</jsp:attribute>
</form:new-game>
<jsp:attribute name="script">
<script defer type="module" src="${pageContext.request.contextPath}/static/js/form/new-game.js"></script>
</jsp:attribute>
<jsp:body>
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">Nouvelle partie</h1>
<form:new-game>
<jsp:attribute name="back_button">
<div class="column">
<a class="button is-fullwidth" href="${pageContext.request.contextPath}/lobby">Revenir au menu</a>
</div>
</jsp:attribute>
</form:new-game>
</div>
</div>
</div>
</div>
</component:hero>
</component:hero>
</jsp:body>
</layout:form>
@@ -7,6 +7,7 @@
<layout:base title="Profil">
<jsp:attribute name="head">
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/form.css"/>
<script defer type="module" src="${pageContext.request.contextPath}/static/js/form/profile.js"></script>
</jsp:attribute>
<jsp:body>
<component:hero>
@@ -4,18 +4,23 @@
<%@taglib prefix="form" tagdir="/WEB-INF/tags/forms" %>
<layout:form title="Inscription">
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">S'inscrire</h1>
<form:register/>
<hr/>
<p class="content has-text-centered">
Déjà inscrit ? <a href="${pageContext.request.contextPath}/login">Se connecter</a>
</p>
<jsp:attribute name="script">
<script defer type="module" src="${pageContext.request.contextPath}/static/js/form/register.js"></script>
</jsp:attribute>
<jsp:body>
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">S'inscrire</h1>
<form:register/>
<hr/>
<p class="content has-text-centered">
Déjà inscrit ? <a href="${pageContext.request.contextPath}/login">Se connecter</a>
</p>
</div>
</div>
</div>
</div>
</component:hero>
</component:hero>
</jsp:body>
</layout:form>
@@ -4,18 +4,23 @@
<%@taglib prefix="component" tagdir="/WEB-INF/tags/components" %>
<layout:form title="Récuperation mot de passe">
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">Récupération de mot de passe</h1>
<form:reset-password/>
<hr/>
<p class="content has-text-centered">
Déjà inscrit ? <a href="${pageContext.request.contextPath}/login">Se connecter</a>
</p>
<jsp:attribute name="script">
<script defer type="module" src="${pageContext.request.contextPath}/static/js/form/reset-password.js"></script>
</jsp:attribute>
<jsp:body>
<component:hero>
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<div class="box">
<h1 class="title has-text-centered">Récupération de mot de passe</h1>
<form:reset-password/>
<hr/>
<p class="content has-text-centered">
Déjà inscrit ? <a href="${pageContext.request.contextPath}/login">Se connecter</a>
</p>
</div>
</div>
</div>
</div>
</component:hero>
</component:hero>
</jsp:body>
</layout:form>
@@ -64,22 +64,3 @@
</div>
</div>
</nav>
<script type="module" defer>
// Récupération de tous les éléments de classe "navbar-burger"
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
// Ajout d'un enventListener sur chaque élément
$navbarBurgers.forEach(el => {
el.addEventListener('click', () => {
// Récupere la valeur de l'attribut "data-target"
const target = el.dataset.target;
const $target = document.getElementById(target);
// Ajoute ou supprime la classe "is-active" sur les éléments
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
</script>
@@ -4,7 +4,7 @@
<div class="field">
<label class="label" for="email">Email</label>
<div class="control has-icons-left">
<input id="email" placeholder="johndoe@exemple.com" class="input is-fullwidth" required/>
<input id="email" name="email" placeholder="johndoe@exemple.com" class="input is-fullwidth" required/>
<span class="icon is-small is-left">
<i class="fas fa-envelope"></i>
</span>
@@ -14,74 +14,34 @@
<input type="submit" class="button is-primary is-fullwidth has-text-white" value="Envoyer">
</form>
<script defer type="module">
const forgottenPasswordForm = document.querySelector("form#forgotten-password-form");
<%--<script defer type="module">--%>
<%-- const forgottenPasswordForm = document.querySelector("form#forgotten-password-form");--%>
// Champ email
const emailInput = document.querySelector("input#email");
<%-- // Champ email--%>
<%-- const inputs = [document.querySelector("input#email")];--%>
// Ajout de l'écouteur d'événement sur la soumission du formulaire
forgottenPasswordForm.addEventListener("submit", onSubmit)
<%-- // Ajout de l'écouteur d'événement sur la soumission du formulaire--%>
<%-- forgottenPasswordForm.addEventListener("submit", onSubmit)--%>
/**
* Gestion de la soumission du formulaire
* @param event {Event} - Événement de soumission du formulaire
*/
function onSubmit(event) {
event.preventDefault();
<%-- /**--%>
<%-- * Gestion de la soumission du formulaire--%>
<%-- * @param event {Event} - Événement de soumission du formulaire--%>
<%-- */--%>
<%-- function onSubmit(event) {--%>
<%-- event.preventDefault();--%>
const {action, method} = forgottenPasswordForm;
<%-- const {action, method} = forgottenPasswordForm;--%>
const url = new URL(action);
url.searchParams.append("email", emailInput.value);
<%-- const url = new URL(action);--%>
<%-- url.searchParams.append("email", emailInput.value);--%>
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
})
.then(() => window.location.href = "${pageContext.request.contextPath}/login")
.catch(onError);
}
/**
* Gestion des erreurs lors de la soumission du formulaire
* @param error {Error} - Erreur survenue lors de la soumission du formulaire
*/
function onError(error) {
console.error("Error:", error)
// Input fields in red
emailInput.classList.add("is-danger");
// Shake the inputs
emailInput.style.animation = "shake 0.5s ease-in-out";
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Erreur";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fas fa-exclamation-triangle'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = error.message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5010);
}
// Retrait des animations sur le champ email
emailInput.addEventListener("animationend", () => emailInput.style.animation = "");
</script>
<%-- fetch(url, {headers: {"Content-Type": "application/json"}, method})--%>
<%-- .then(res => res.json())--%>
<%-- .then(data => {--%>
<%-- if (data.code !== 200) throw new Error(data.message);--%>
<%-- })--%>
<%-- .then(() => window.location.href = "${pageContext.request.contextPath}/login")--%>
<%-- .catch(onError);--%>
<%-- }--%>
<%--</script>--%>
@@ -28,59 +28,3 @@
<input type="submit" class="button is-primary has-text-white is-fullwidth" value="Connexion">
</form>
<script defer type="module">
const form = document.querySelector("form#login-form");
const inputs = form.querySelectorAll("input[type='text'], input[type='password']");
form.addEventListener("submit", event => {
event.preventDefault();
const {action, method} = form;
const url = new URL(action);
inputs.forEach(input => url.searchParams.append(input.getAttribute("name"), input.value));
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
})
.then(() => window.location.href = "${pageContext.request.contextPath}/lobby")
.catch((error) => {
// Animations des champs
inputs.forEach(input => {
input.classList.add("is-danger");
input.style.animation = "shake 0.5s ease-in-out"
});
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Erreur";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fas fa-exclamation-triangle'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = error.message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
// Retirer la notification et les animations après 5 secondes
setTimeout(() => notification.remove(), 5010);
});
});
// Retirer les animations des champs après la fin de l'animation
inputs.forEach(input => input.addEventListener("animationend", () => input.style.animation = ""));
</script>
@@ -82,80 +82,4 @@
</form>
<style>
label.radio.button > input[type="radio"] {
display: none;
}
</style>
<script defer type="module">
const nbRound = document.querySelector("input[name='nbRounds']");
const nbValues = document.querySelector("input[name='nbValues']");
const nbColors = document.querySelector("input[name='nbColors']");
const rangeInputs = document.querySelectorAll("input[type='range']");
rangeInputs.forEach(input => {
const tooltip = document.querySelector(input.dataset.tooltip);
input.addEventListener("input", () => {
tooltip.innerHTML = input.value
nbRound.max = nbValues.value * nbColors.value;
nbRound.value = parseInt(nbRound.value) > parseInt(nbRound.max) ? nbRound.max : nbRoundtmp;
});
});
const radioButtons = document.querySelectorAll('input[type="radio"]');
radioButtons.forEach(radio => {
radio.addEventListener('change', () => {
radioButtons.forEach(radio => radio.parentElement.classList.remove('is-primary'));
radio.parentElement.classList.add('is-primary');
});
});
const form = document.getElementById('new-game-form');
form.addEventListener('submit', evt => {
evt.preventDefault();
const {action, method} = form;
const url = new URL(action);
const formData = new FormData(form);
for (const [key, value] of formData.entries()) {
url.searchParams.append(key, value);
}
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
// Redirection vers la page de jeu
window.location.href = "${pageContext.request.contextPath}/game?id=" + data.message;
})
.catch((error) => {
console.log(error)
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Erreur";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fas fa-exclamation-triangle'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = error.message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
// Retrait de la notification et des animations après 5 secondes
setTimeout(() => notification.remove(), 5010);
});
});
</script>
@@ -88,110 +88,3 @@
</div>
</div>
</form>
<script defer type="module">
const profileForm = document.querySelector("form#profile-form");
const changePassword = profileForm.querySelector("a#change-password");
const passwordFields = profileForm.querySelectorAll("div#old-password-field, div#password-field, div#repeat-password-field");
const inputs = profileForm.querySelectorAll("input[type='text'], input[type='password']");
// Afficher les champs de mot de passe si le lien est cliqué
changePassword.addEventListener("click", (e) => {
e.preventDefault();
passwordFields.forEach(field => {
field.style.display = "block";
});
});
profileForm.addEventListener("submit", onSubmit);
function onSubmit(event) {
event.preventDefault();
const oldPassword = profileForm.querySelector("input[name='oldPassword']");
const password = profileForm.querySelector("input[name='password']");
const repassword = profileForm.querySelector("input[name='repeat-password']");
// Check if the password and the confirmation password are the same
if (oldPassword.value !== "" && password.value !== repassword.value) {
onError(new Error("Les mots de passe ne correspondent pas"));
return;
}
const {action, method} = profileForm;
const url = new URL(action);
const formData = new FormData(profileForm);
for (const [key, value] of formData.entries()) {
url.searchParams.append(key, value);
}
url.searchParams.append("id", ${user.id})
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
onSuccess()
})
.catch(onError)
}
function onError(error) {
console.log(error)
// Input fields in red
inputs.forEach(input => input.classList.add("is-danger"));
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Erreur";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fas fa-exclamation-triangle'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = error.message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
setTimeout(() => {
notification.remove()
inputs.forEach(input => input.classList.remove("is-danger"));
}, 5010);
}
function onSuccess() {
console.log("Succès:", "Modifications effectuées avec succès")
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-success");
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Succès";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fa-solid fa-check'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = "Le profil a été modifié avec succès";
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5010);
}
inputs.forEach(input => input.addEventListener("animationend", () => input.style.animation = ""));
</script>
@@ -56,69 +56,3 @@
<input type="submit" class="button has-text-white is-primary is-fullwidth" value="S'inscrire">
</form>
<script defer type="module">
const registerForm = document.querySelector("form#register-form");
const inputs = registerForm.querySelectorAll("input, select");
registerForm.addEventListener("submit", onSubmit)
function onSubmit(event) {
event.preventDefault();
const password = registerForm.querySelector("input[name='password']");
const repassword = registerForm.querySelector("input[name='repassword']");
// Check if the password and the confirmation password are the same
if (password.value !== repassword.value) {
onError(new Error("Les mots de passe ne correspondent pas"));
return;
}
const {action, method} = registerForm;
const url = new URL(action);
inputs.forEach(input => url.searchParams.append(input.name, input.value));
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
})
.then(() => window.location.href = "${pageContext.request.contextPath}/login")
.catch(onError)
}
function onError(error) {
console.error("Error:", error)
// Input fields in red
inputs.forEach(input => input.classList.add("is-danger"));
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Erreur";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fas fa-exclamation-triangle'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = error.message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5010);
}
</script>
@@ -21,76 +21,3 @@
<input type="submit" class="button is-primary has-text-white is-fullwidth" value="Envoyer">
</form>
<script defer type="module">
const resetPasswordForm = document.querySelector("form#reset-password-form");
const submitButton = document.querySelector("input[type=submit]");
const inputs = resetPasswordForm.querySelectorAll("input[type='text'], input[type='password']");
const tokenInput = document.querySelector("input#token");
const passwordInput = document.querySelector("input#password");
const repasswordInput = document.querySelector("input#repassword");
resetPasswordForm.addEventListener("submit", onSubmit)
function onSubmit(event) {
event.preventDefault();
// Check if the password and the confirmation password are the same
if (passwordInput.value !== repasswordInput.value) {
onError(new Error("Les mots de passe ne correspondent pas"));
return;
}
const {action, method} = resetPasswordForm;
const url = new URL(action);
url.searchParams.append("token", tokenInput.value);
url.searchParams.append("password", passwordInput.value);
submitButton.classList.add("is-loading");
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
})
.then(() => window.location.href = "${pageContext.request.contextPath}/login")
.catch(onError)
.finally(() => submitButton.classList.remove("is-loading"));
}
function onError(error) {
console.error("Error:", error)
inputs.forEach(input => {
input.classList.add("is-danger");
input.style.animation = "shake 0.5s ease-in-out"
});
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Erreur";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fas fa-exclamation-triangle'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = error.message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5010);
}
inputs.forEach(input => input.addEventListener("animationend", () => input.style.animation = ""));
</script>
@@ -3,7 +3,6 @@
<%@attribute name="title"%>
<%@attribute name="head" fragment="true" %>
<%@taglib prefix="component" tagdir="/WEB-INF/tags/components" %>
<!DOCTYPE html>
@@ -17,7 +16,10 @@
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css">
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/global.css">
<script defer type="module" src="${pageContext.request.contextPath}/static/js/navbar.js"></script>
<script defer type="module" src="${pageContext.request.contextPath}/static/js/notification/error.js"></script>
<script defer type="module" src="${pageContext.request.contextPath}/static/js/notification/success.js"></script>
<script defer type="module" src="${pageContext.request.contextPath}/static/js/notification/invite.js"></script>
<jsp:invoke fragment="head"/>
</head>
<body>
@@ -27,4 +29,4 @@
<component:footer/>
</body>
</html>
</html>
@@ -3,13 +3,15 @@
<%@taglib prefix="layout" tagdir="/WEB-INF/tags/layouts" %>
<%@attribute name="title"%>
<%@attribute name="script" fragment="true" %>
<layout:base title="${title}">
<jsp:attribute name="head">
<link rel="stylesheet" href="${pageContext.request.contextPath}/static/css/form.css"/>
<jsp:invoke fragment="script"/>
</jsp:attribute>
<jsp:body>
<jsp:doBody/>
</jsp:body>
</layout:base>
</layout:base>
@@ -9,6 +9,10 @@
background: url("../img/Home.svg") lightgray 50% / cover no-repeat;
}
label.radio.button > input[type="radio"] {
display: none;
}
@media screen and (min-width: 769px) {
.modal-card, .modal-content {
width: var(--modal-content-width) !important;
@@ -0,0 +1,30 @@
import {onError} from "../notification/error.js";
const forgottenPasswordForm = document.querySelector("form#forgotten-password-form");
// Champ email
const inputs = [document.querySelector("input#email")];
// Ajout de l'écouteur d'événement sur la soumission du formulaire
forgottenPasswordForm.addEventListener("submit", onSubmit)
/**
* Gestion de la soumission du formulaire
* @param event {Event} - Événement de soumission du formulaire
*/
function onSubmit(event) {
event.preventDefault();
const {action, method} = forgottenPasswordForm;
const url = new URL(action);
const contextPath = url.href.substring(0, url.href.lastIndexOf("/") + 1);
inputs.forEach(input => url.searchParams.append(input.getAttribute("name"), input.value));
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
})
.then(() => window.location.href = contextPath+"login?success=forgotten-password")
.catch((error) => onError(error, inputs));
}
@@ -0,0 +1,30 @@
import {onError} from "../notification/error.js";
import {onSuccess} from "../notification/success.js";
import {verifSuccess} from "../notification/success.js";
//Vérifier si un formulaire a été soumis avec succès
verifSuccess();
const form = document.querySelector("form#login-form");
const inputs = form.querySelectorAll("input[type='text'], input[type='password']");
form.addEventListener("submit", event => {
event.preventDefault();
const {action, method} = form;
const url = new URL(action);
const contextPath = url.href.substring(0, url.href.lastIndexOf("/") + 1);
inputs.forEach(input => url.searchParams.append(input.getAttribute("name"), input.value));
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
})
.then(() => window.location.href = contextPath + "lobby")
.catch((error) => onError(error, inputs))
});
// Retirer les animations des champs après la fin de l'animation
inputs.forEach(input => input.addEventListener("animationend", () => input.style.animation = ""));
@@ -0,0 +1,52 @@
import {onError} from "../notification/error.js";
const nbRound = document.querySelector("input[name='nbRounds']");
const nbValues = document.querySelector("input[name='nbValues']");
const nbColors = document.querySelector("input[name='nbColors']");
const rangeInputs = document.querySelectorAll("input[type='range']");
rangeInputs.forEach(input => updateMaxRound(input));
const radioButtons = document.querySelectorAll('input[type="radio"]');
radioButtons.forEach(radio => updateRadio(radio));
const form = document.getElementById('new-game-form');
form.addEventListener('submit', evt => {
evt.preventDefault();
const {action, method} = form;
const url = new URL(action);
const contextPath = url.href.substring(0, url.href.lastIndexOf("/") + 1);
const formData = new FormData(form);
for (const [key, value] of formData.entries()) {
url.searchParams.append(key, value);
}
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
// Redirection vers la page de jeu
window.location.href = contextPath + "game?id=" + data.message;
})
.catch((error) => onError(error.message, inputs))
});
function updateMaxRound(input) {
const tooltip = document.querySelector(input.dataset.tooltip);
input.addEventListener("input", () => {
tooltip.innerHTML = input.value
nbRound.max = nbValues.value * nbColors.value;
nbRound.value = parseInt(nbRound.value) > parseInt(nbRound.max) ? nbRound.max : nbRound.value;
})
}
function updateRadio(radio) {
radio.addEventListener('change', () => {
radioButtons.forEach(radio => radio.parentElement.classList.remove('is-primary'));
radio.parentElement.classList.add('is-primary');
});
}
@@ -0,0 +1,52 @@
import {onError} from "../notification/error.js";
import {onSuccess} from "../notification/success.js";
import {Success} from "../notification/success.js";
const profileForm = document.querySelector("form#profile-form");
const username = profileForm.querySelector("input[name='username']");
const changePassword = profileForm.querySelector("a#change-password");
const passwordFields = profileForm.querySelectorAll("div#old-password-field, div#password-field, div#repeat-password-field");
const inputs = profileForm.querySelectorAll("input[type='text'], input[type='email'], input[type='password']");
// Afficher les champs de mot de passe si le lien est cliqué
changePassword.addEventListener("click", (e) => {
e.preventDefault();
passwordFields.forEach(field => {
field.style.display = "block";
});
});
profileForm.addEventListener("submit", onSubmit);
function onSubmit(event) {
event.preventDefault();
const oldPassword = profileForm.querySelector("input[name='oldPassword']");
const password = profileForm.querySelector("input[name='password']");
const repassword = profileForm.querySelector("input[name='repeat-password']");
// Check if the password and the confirmation password are the same
if (oldPassword.value !== "" && password.value !== repassword.value) {
onError(new Error("Les mots de passe ne correspondent pas"), [oldPassword, password, repassword]);
return;
}
const {action, method} = profileForm;
const url = new URL(action);
const contextPath = url.href.substring(0, url.href.lastIndexOf("/") + 1);
const formData = new FormData(profileForm);
for (const [key, value] of formData.entries()) {
url.searchParams.append(key, value);
}
url.searchParams.append("username", username.value);
url.searchParams.forEach((value, key) => console.log(key, value));
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) throw new Error(data.message);
onSuccess(Success.PROFILE_UPDATED)
})
.catch((error) => onError(error, inputs))
}
@@ -0,0 +1,37 @@
import {onError} from "../notification/error.js";
const registerForm = document.querySelector("form#register-form");
const inputs = registerForm.querySelectorAll("input, select");
registerForm.addEventListener("submit", onSubmit)
function onSubmit(event) {
event.preventDefault();
const password = registerForm.querySelector("input[name='password']");
const repassword = registerForm.querySelector("input[name='repassword']");
// Check if the password and the confirmation password are the same
if (password.value !== repassword.value) {
onError( new Error("Les mots de passe ne correspondent pas"),[password, repassword]);
return;
}
const {action, method} = registerForm;
const url = new URL(action);
const contextPath = url.href.substring(0, url.href.lastIndexOf("/") + 1);
inputs.forEach(input => url.searchParams.append(input.name, input.value));
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) {
throw new Error(data.message);
}
})
.then(() => window.location.href = contextPath+"login?success=create-account")
.catch((error) => onError(error, inputs)
)
}
@@ -0,0 +1,44 @@
import {onError} from "../notification/error.js";
const resetPasswordForm = document.querySelector("form#reset-password-form");
const submitButton = document.querySelector("input[type=submit]");
const inputs = resetPasswordForm.querySelectorAll("input[type='password']");
const tokenInput = document.querySelector("input#token");
const passwordInput = document.querySelector("input#password");
const repasswordInput = document.querySelector("input#repassword");
resetPasswordForm.addEventListener("submit", onSubmit)
function onSubmit(event) {
event.preventDefault();
// Check if the password and the confirmation password are the same
if (passwordInput.value !== repasswordInput.value) {
onError(new Error("Les mots de passe ne correspondent pas"), inputs);
return;
}
const {action, method} = resetPasswordForm;
const url = new URL(action);
const contextPath = url.href.substring(0, url.href.lastIndexOf("/") + 1);
inputs.forEach(input => url.searchParams.append(input.getAttribute("name"), input.value));
url.searchParams.append("token", tokenInput.value);
submitButton.classList.add("is-loading");
fetch(url, {headers: {"Content-Type": "application/json"}, method})
.then(res => res.json())
.then(data => {
if (data.code !== 200) {
throw new Error(data.message);
}
})
.then(() => window.location.href = contextPath+"login?success=reset-password")
.catch((error) => {
console.log(inputs);
onError(error, inputs);
}
)
.finally(() => submitButton.classList.remove("is-loading"));
}
@@ -0,0 +1,16 @@
// Récupération de tous les éléments de classe "navbar-burger"
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
// Ajout d'un enventListener sur chaque élément
$navbarBurgers.forEach(el => {
el.addEventListener('click', () => {
// Récupere la valeur de l'attribut "data-target"
const target = el.dataset.target;
const $target = document.getElementById(target);
// Ajoute ou supprime la classe "is-active" sur les éléments
el.classList.toggle('is-active');
$target.classList.toggle('is-active');
});
});
@@ -0,0 +1,35 @@
export function onError(error, inputs) {
// Animations des champs
inputs.forEach(input => {
input.classList.add("is-danger");
input.style.animation = "shake 0.5s ease-in-out"
});
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Erreur";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fas fa-exclamation-triangle'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = error.message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
// Retirer la notification et les animations après 5 secondes
setTimeout(() => {
notification.remove()
inputs.forEach(input => input.classList.remove("is-danger"));
}, 5010);
inputs.forEach(input => input.addEventListener("animationend", () => input.style.animation = ""));
};
@@ -0,0 +1,57 @@
export class Success {
static successKeys = {
FORGOTTEN_PASSWORD: "forgotten-password",
RESET_PASSWORD: "reset-password",
UPDATE_PROFILE: "update-profile",
CREATE_ACCOUNT: "create-account",
}
static successValues = {
FORGOTTEN_PASSWORD: "Un email vous a été envoyé pour réinitialiser votre mot de passe",
RESET_PASSWORD: "Mot de passe récupéré avec succès",
UPDATE_PROFILE: "Profil modifié avec succès",
CREATE_ACCOUNT: "Compte créé avec succès",
}
}
export function onSuccess(message) {
console.log("Succès:", "Modifications effectuées avec succès")
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-success");
const notificationTitle = document.createElement("p");
notificationTitle.classList.add("title", "is-6");
notificationTitle.innerHTML = "Succès";
const notificationIcon = document.createElement("span");
notificationIcon.classList.add("icon");
notificationIcon.innerHTML = "<i class='fa-solid fa-check'></i>";
const notificationMessage = document.createElement("p");
notificationMessage.classList.add("subtitle", "is-6");
notificationMessage.innerHTML = message;
notificationTitle.appendChild(notificationIcon);
notification.appendChild(notificationTitle);
notification.appendChild(notificationMessage);
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 5010);
}
export function verifSuccess(){
const url = new URL(window.location.href);
if (url.searchParams.get("success")!=undefined && url.searchParams.get("success") === Success.successKeys.FORGOTTEN_PASSWORD) {
onSuccess(Success.successValues.FORGOTTEN_PASSWORD)
}
if (url.searchParams.get("success")!=undefined && url.searchParams.get("success") === Success.successKeys.RESET_PASSWORD) {
onSuccess(Success.successValues.RESET_PASSWORD)
}
if (url.searchParams.get("success")!=undefined && url.searchParams.get("success") === Success.successKeys.CREATE_ACCOUNT) {
onSuccess(Success.successValues.CREATE_ACCOUNT)
}
if (url.searchParams.get("success")!=undefined && url.searchParams.get("success") === Success.successKeys.UPDATE_PROFILE) {
onSuccess(Success.successValues.UPDATE_PROFILE)
}
}