feat: devWeb - update profile page

This commit is contained in:
kmitresse
2024-04-26 22:17:15 +02:00
parent 350011cb66
commit 93d6677449
7 changed files with 491 additions and 88 deletions
@@ -1,4 +1,10 @@
<%@ page import="uppa.project.database.pojo.Player" %>
<%@ page import="uppa.project.database.pojo.Game" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%--<%@ taglib uri = "https://mvnrepository.com/artifact/jakarta.servlet.jsp.jstl/jakarta.servlet.jsp.jstl-api" prefix = "c" %>--%>
<%@taglib prefix="layout" tagdir="/WEB-INF/tags/layouts" %>
<%@taglib prefix="component" tagdir="/WEB-INF/tags/components" %>
@@ -9,93 +15,38 @@
<div class="columns is-centered">
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<component:card title="Profil">
<fieldset disabled>
<jsp:useBean id="user" class="uppa.project.database.pojo.User" scope="session"/>
<div class="field">
<label class="label">Nom d'utilisateur</label>
<input class="input" type="text" value="${user.username}">
</div>
<div class="field">
<label class="label">Email</label>
<input class="input" type="text" value="${user.email}">
</div>
<div class="field">
<label class="label">Mot de passe</label>
<a href="/profile/password">Changer le mot de passe</a>
</div>
<div class="field">
<label class="label">Date de naissance</label>
<input class="input" type="text" value="${user.birth.toLocaleString()}">
</div>
<div class="field">
<label class="label">Genre</label>
<input class="input" type="text" value="${user.gender}">
</div>
<fieldset>
<form:profile/>
</fieldset>
<div class="buttons">
<button class="button is-primary is-outlined">Modifier</button>
<button class="button is-primary has-text-white">Supprimer le compte</button>
</div>
</component:card>
</div>
<div class="column is-5-tablet is-5-desktop is-5-widescreen">
<component:card title="Statistiques">
<h4 class="title is-4">Statistiques globales</h4>
<div class="level">
<div class="level-item has-text-centered">
<div>
<p class="heading">Parties</p>
<p class="title">${user.nbPlayedGame}</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="heading">Victoires</p>
<p class="title">${user.nbWin}</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="heading">Clics corrects</p>
<p class="title">${user.nbRightClicks}</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="heading">Clics rapides</p>
<p class="title">${user.nbRapidClicks}</p>
</div>
</div>
</div>
<%-- TODO: Tableau des 10 dernières parties--%>
<h4 class="title is-4">10 dernières parties</h4>
<table class="table is-fullwidth">
<thead>
<tr>
<th>Date</th>
<th>Victoire</th>
<th>Score</th>
<th></th>
</tr>
</thead>
<tbody>
<c:forEach var="game" items="${user.playedGames}">
<tr>
<td>${game.createdAt}</td>
<td>${game.winner}</td>
<td>${game.score}</td>
<td><a href="/game/${game.id}">Voir</a></td>
</tr>
</c:forEach>
</table>
<component:statistics/>
</component:card>
</div>
</div>
</component:hero>
</layout:base>
</layout:base>
<script defer type="text/javascript">
const gameList = document.getElementById('game-list');
console.log("gameList", gameList)
${user.playedGames}.forEach((player) => {
console.log("player", player)
gameListTr = document.createElement('tr');
gameListTdDate = document.createElement('td');
gameListTdDate.innerHTML = player.game.createdAt;
gameListTdScore = document.createElement('td');
gameListTdScore.innerHTML = player.score;
gameListTdWinner = document.createElement('td');
gameListTdWinner.innerHTML = player.game.winner;
gameListTdLink = document.createElement('td');
gameListTdLink.innerHTML = `<a href="/game/${player.game.id}">Voir</a>`;
gameListTr.appendChild(gameListTdDate);
gameListTr.appendChild(gameListTdScore);
gameListTr.appendChild(gameListTdWinner);
gameListTr.appendChild(gameListTdLink);
})
</script>
@@ -0,0 +1,64 @@
<%@ tag import="uppa.project.database.pojo.Player" %>
<%@tag description="component/statistics" pageEncoding="UTF-8" %>
<jsp:useBean id="user" class="uppa.project.database.pojo.User" scope="session"/>
<h4 class="title is-4">Statistiques globales</h4>
<div class="level">
<div class="level-item has-text-centered">
<div>
<p class="heading">Parties</p>
<p class="title">${user.nbPlayedGame}</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="heading">Victoires</p>
<p class="title">${user.nbWin}</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="heading">Clics corrects</p>
<p class="title">${user.rightClickPercentRate}%</p>
</div>
</div>
<div class="level-item has-text-centered">
<div>
<p class="heading">Clics rapides</p>
<p class="title">${user.rapidClickPercentRate}%</p>
</div>
</div>
</div>
<%-- TODO: Si le temps nous le permet, mettre en place un système de pagination --%>
<h4 class="title is-4">Parties jouées </h4>
<table class="table is-fullwidth">
<thead>
<tr>
<th>Date</th>
<th>Score</th>
<th>Vainqueur</th>
<th></th>
</tr>
</thead>
<tbody id="game-list">
<% for (int i = 0; i < user.getPlayedGames().size(); i++) {
Player player = user.getPlayedGames().get(i);
%>
<tr>
<td><%= player.getGame().getCreatedAt().toLocaleString() %></td>
<td><%= player.getScore() %></td>
<td><%= player.getGame().getWinner() %></td>
<td><a href="/game/<%= player.getGame().getId() %>">Voir</a></td>
</tr>
<% } %>
<%-- <c:forEach var="player" items="${user.playedGames}">--%>
<%-- <tr>--%>
<%-- <td>${player.game.createdAt}</td>--%>
<%-- <td>${player.score}</td>--%>
<%-- <td>${player.game.winner}</td>--%>
<%-- <td><a href="/game/${player.game.id}">Voir</a></td>--%>
<%-- </tr>--%>
</tbody>
</table>
@@ -1,5 +1,207 @@
<%@ tag import="uppa.project.database.pojo.User" %>
<%@tag description="form/profile" pageEncoding="UTF-8" %>
<form id="profile-form" action="${pageContext.request.contextPath}/reset-password" method="post">
<form id="profile-form" action="${pageContext.request.contextPath}/profile" method="post">
<jsp:useBean id="user" class="uppa.project.database.pojo.User" scope="session"/>
<div class="field">
<label class="label" for="username">Nom d'utilisateur</label>
<div class="control has-icons-left">
<input id="username" name="username" value="${user.username}" type="text" class="input is-fullwidth" disabled/>
<span class="icon is-left"><i class="fas fa-user"></i></span>
</div>
</div>
<div class="field">
<label class="label" for="email">Email</label>
<div class="control has-icons-left">
<input id="old-email" name="oldEmail" type="hidden" value="${user.email}" class="input is-fullwidth" required>
<input id="email" name="email" type="email" value="${user.email}" class="input is-fullwidth" required>
<span class="icon is-left"><i class="fas fa-envelope"></i></span>
</div>
</div>
<div class="field">
<label class="label">Mot de passe</label>
<a id="change-password" href="#">Changer le mot de passe</a>
</div>
<div id="old-password-field" class="field" style="display: none">
<div class="control has-icons-left">
<input id="old-password" name="oldPassword" placeholder="Ancien mot de passe" type="password" class="input is-fullwidth">
<span class="icon is-left"><i class="fas fa-lock"></i></span>
</div>
</div>
<div id="password-field" class="field" style="display: none">
<div class="control has-icons-left">
<input id="password" name="password" placeholder="Nouveau mot de passe" type="password" class="input is-fullwidth">
<span class="icon is-left"><i class="fas fa-lock"></i></span>
</div>
</div>
<div id="repeat-password-field" class="field" style="display: none">
<div class="control has-icons-left">
<input id="repeat-password" name="repeat-password" placeholder="Confirmer le mot de passe" type="password" class="input is-fullwidth">
<span class="icon is-left"><i class="fas fa-lock"></i></span>
</div>
</div>
<div class="field">
<label class="label">Date de naissance</label>
<input class="input" type="text" value="${user.birth.toLocaleString()}" disabled>
</div>
<div class="field">
<label class="label" for="gender">Genre</label>
<div class="control has-icons-left">
<div class="select is-fullwidth">
<input id="old-gender" name="oldGender" type="hidden" value="${user.gender.name()}" class="input is-fullwidth" required>
<select name="gender" id="gender" required>
<% if (user.getGender() == null) { %>
<option selected value="">- Choisissez une option -</option>
<% } else { %>
<option value="">- Choisissez une option -</option>
<% } %>
<% if (user.getGender().equals(User.Gender.MALE)) {%>
<option selected value="MALE">Homme</option>
<% } else { %>
<option value="MALE">Homme</option>
<% } %>
<% if (user.getGender().equals(User.Gender.FEMALE)) {%>
<option selected value="FEMALE">Femme</option>
<% } else { %>
<option value="FEMALE">Femme</option>
<% } %>
<% if (user.getGender().equals(User.Gender.OTHER)) {%>
<option selected value="OTHER">Autre</option>
<% } else { %>
<option value="OTHER">Autre</option>
<% } %>
</select>
</div>
<span class="icon is-left"><i class="fa-solid fa-venus-mars"></i></span>
</div>
</div>
</form>
<div class="field">
<div class="buttons is-right">
<input type="submit" id="modify" class="button is-primary is-outlined" value="Modifier">
</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']");
changePassword.addEventListener("click", (e) => {
e.preventDefault();
passwordFields.forEach(field => {
console.log(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 !== "") {
if("${User.hashPassword(oldPassword.value)}" !== "${user.password}"){
onError(new Error("L'ancien mot de passe ne corresponds pas"));
return;
}
if(password.value !== repassword.value) {
onError(new Error("Les mots de passe ne correspondent pas"));
return;
}
}
else {
password.value = "${user.password}";
};
const {action, method} = profileForm;
const url = new URL(action);
const formData = new FormData(profileForm);
for (const [key, value] of formData.entries()) {
console.log(key, value);
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 => {
console.log(data)
if (data.code !== 200) throw new Error(data.message);
onSuccess()
})
.catch(onError)
}
/**
* Handle the error of the form submission
* @param error {Error} - Error of the form submission
*/
function onError(error) {
console.log("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);
}
/**
* Handle the success of the form submission
*/
function onSuccess() {
console.log("Succes:", "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='fas fa-exclamation-triangle'></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>
@@ -24,6 +24,8 @@
<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']");
// Form fields
const tokenInput = document.querySelector("input#token");
@@ -68,18 +70,39 @@
* @param error {Error} - Error of the form submission
*/
function onError(error) {
console.error("Error:", error)
console.error("Error:", error)
// Input fields in red
passwordInput.classList.add("is-danger");
repasswordInput.classList.add("is-danger");
// Input fields in red
inputs.forEach(input => {
input.classList.add("is-danger");
input.style.animation = "shake 0.5s ease-in-out"
});
// Notification
// Notification
const notification = document.createElement("div");
notification.classList.add("notification", "is-danger");
notification.innerHTML = error.message;
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>