Ajout de la page de profil

This commit is contained in:
Mathis 2025-04-11 19:48:50 +02:00
parent f868effc9a
commit 6bcdcedc66
11 changed files with 581 additions and 214 deletions

View File

@ -30,8 +30,9 @@ public class AuthHandler {
String email = body.getString("email");
String gender = body.getString("gender");
String password = body.getString("password");
String pseudo = body.getString("pseudo");
if (name == null || surname == null || email == null || gender == null || password == null) {
if (name == null || surname == null || email == null || gender == null || password == null || pseudo == null) {
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error", "Tous les champs sont requis").encode());
@ -41,8 +42,8 @@ public class AuthHandler {
String hashedPassword = BCrypt.withDefaults().hashToString(12, password.toCharArray());
databaseService.pool
.preparedQuery("INSERT INTO users (name, surname, email, gender, password) VALUES (?, ?, ?, ?, ?)")
.execute(Tuple.of(name, surname, email, gender, hashedPassword))
.preparedQuery("INSERT INTO users (name, surname, email, gender, password, pseudo) VALUES (?, ?, ?, ?, ?, ?)")
.execute(Tuple.of(name, surname, email, gender, hashedPassword,pseudo))
.onSuccess(result -> {
context.response()
.setStatusCode(201)

View File

@ -56,13 +56,17 @@ public class MainVerticle extends AbstractVerticle {
router.post("/modifRangeData").handler(setWeatherData::setRangeData);
router.post("/deleteObject").handler(setObjects::deleteObject);
router.get("/users").handler(queryUsers::getUsers);
router.post("/user").handler(queryUsers::getUser);
router.post("/setUserPoints").handler(setUser::setUserPoints);
router.post("/deleteUser").handler(setUser::deleteUser);
router.post("/updateProfil").handler(setUser::updateUserProfile);
router.post("/changePassword").handler(setUser::changeUserPassword);
// Routes d'authentification
router.post("/signup").handler(authHandler::handleSignup);
router.post("/login").handler(authHandler::handleLogin);
// Création du serveur HTTP
vertx.createHttpServer()
.requestHandler(router)

View File

@ -4,6 +4,7 @@ import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import io.vertx.sqlclient.Row;
import io.vertx.sqlclient.Tuple;
public class QueryUsers {
private DatabaseService databaseService;
@ -25,19 +26,20 @@ public class QueryUsers {
.onSuccess(rows -> {
JsonArray users = new JsonArray();
for (Row row : rows) {
int points=row.getInteger("points");
int points = row.getInteger("points");
JsonObject user = new JsonObject()
.put("id", row.getInteger("id"))
.put("name", row.getString("name"))
.put("surname", row.getString("surname"))
.put("email", row.getString("email"))
.put("gender", row.getString("gender"))
.put("points",points);
if(points<=60){
.put("pseudo",row.getString("pseudo"))
.put("points", points);
if (points <= 60) {
user.put("role", "user");
}else if(points<=100){
} else if (points <= 100) {
user.put("role", "complexe");
}else if(points>=200){
} else if (points >= 200) {
user.put("role", "admin");
}
users.add(user);
@ -48,4 +50,56 @@ public class QueryUsers {
});
}
public void getUser(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
if (body == null) {
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
return;
}
//Integer idUser = body.getInteger("idUser");
Integer idUser = 4;
databaseService.pool
.preparedQuery("SELECT * FROM users WHERE id=?;")
.execute(Tuple.of(idUser))
.onFailure(e -> {
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject().put("error", "Erreur de récupération de la BDD").encode());
})
.onSuccess(rows -> {
if (rows.size() == 0) {
context.response()
.setStatusCode(404)
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
return;
}
Row row = rows.iterator().next();
int points = row.getInteger("points");
JsonObject user = new JsonObject()
.put("id", row.getInteger("id"))
.put("name", row.getString("name"))
.put("surname", row.getString("surname"))
.put("email", row.getString("email"))
.put("gender", row.getString("gender"))
.put("pseudo",row.getString("pseudo"))
.put("points", points);
if (points <= 60) {
user.put("role", "user");
} else if (points <= 100) {
user.put("role", "complexe");
} else if (points >= 200) {
user.put("role", "admin");
}
context.response()
.putHeader("content-type", "application/json; charset=UTF-8")
.end(user.encode());
});
}
}

View File

@ -1,5 +1,6 @@
package com.example.starter;
import at.favre.lib.crypto.bcrypt.BCrypt;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import io.vertx.sqlclient.Tuple;
@ -10,6 +11,7 @@ public class SetUser {
public SetUser(DatabaseService ddbs) {
this.databaseService = ddbs;
}
public void updateUserPoints(Integer userId, Integer points) {
databaseService.pool
.preparedQuery("UPDATE users SET points=points+? WHERE id=?")
@ -25,6 +27,105 @@ public class SetUser {
}
});
}
public void changeUserPassword(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
if (body == null) {
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
return;
}
Integer id = body.getInteger("id");
String oldPassword = body.getString("oldPassword");
String newPassword = body.getString("newPassword");
databaseService.pool
.preparedQuery("SELECT password FROM users WHERE id=?")
.execute(Tuple.of(id))
.onFailure(e -> {
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject().put("error", "Erreur de récupération de la BDD").encode());
})
.onSuccess(rows -> {
if (rows.rowCount() == 0) {
context.response()
.setStatusCode(404)
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
return;
}
String currentPassword = rows.iterator().next().getString("password");
BCrypt.Result verification = BCrypt.verifyer().verify(oldPassword.toCharArray(), currentPassword);
if (!verification.verified) {
context.response()
.setStatusCode(401)
.end(new JsonObject().put("error", "Ancien mot de passe incorrect").encode());
return;
}
String hashedPassword = BCrypt.withDefaults().hashToString(12, newPassword.toCharArray());
databaseService.pool
.preparedQuery("UPDATE users SET password=? WHERE id=?")
.execute(Tuple.of(hashedPassword, id))
.onFailure(e -> {
System.err.println("Erreur lors de la mise à jour du mot de passe :" + e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject()
.put("error", "Erreur lors de la mise à jour du mot de passe")
.encode());
})
.onSuccess(updateRows -> {
context.response()
.putHeader("content-type", "application/json: charset=UTF-8")
.end(new JsonObject().put("success", "Le mot de passe a bien été mis à jour")
.encode());
});
});
}
public void updateUserProfile(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
if (body == null) {
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
return;
}
Integer id = body.getInteger("id");
String name = body.getString("name");
String surname = body.getString("surname");
String pseudo = body.getString("pseudo");
databaseService.pool
.preparedQuery("UPDATE users SET name=?, surname=?, pseudo=? WHERE id=?")
.execute(Tuple.of(name, surname,pseudo, id))
.onFailure(e -> {
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject().put("error", "Erreur de récupération de la BDD").encode());
})
.onSuccess(rows -> {
if (rows.rowCount() == 0) {
context.response()
.setStatusCode(404)
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
return;
}
context.response()
.putHeader("content-type", "application/json: charset=UTF-8")
.end(new JsonObject()
.put("success", "Les informations de l'utilisateur ont bien été mises à jour")
.encode());
return;
});
}
public void setUserPoints(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
if (body == null) {
@ -59,36 +160,37 @@ public class SetUser {
return;
});
}
public void deleteUser(RoutingContext context){
public void deleteUser(RoutingContext context) {
JsonObject body = context.body().asJsonObject();
if(body== null){
if (body == null) {
context.response()
.setStatusCode(400)
.end(new JsonObject().put("error","Corps de la requête manquant").encode());
.setStatusCode(400)
.end(new JsonObject().put("error", "Corps de la requête manquant").encode());
return;
}
Integer id = body.getInteger("id");
databaseService.pool
.preparedQuery("DELETE FROM users WHERE id=?")
.execute(Tuple.of(id))
.onFailure(e->{
System.err.println("Erreur de récupération de la BDD :"+e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject().put("error","Erreur de récupération de la BDD").encode());
})
.onSuccess(rows -> {
if(rows.rowCount()==0){
.preparedQuery("DELETE FROM users WHERE id=?")
.execute(Tuple.of(id))
.onFailure(e -> {
System.err.println("Erreur de récupération de la BDD :" + e.getMessage());
context.response()
.setStatusCode(500)
.end(new JsonObject().put("error", "Erreur de récupération de la BDD").encode());
})
.onSuccess(rows -> {
if (rows.rowCount() == 0) {
context.response()
.setStatusCode(404)
.end(new JsonObject().put("error", "Utilisateur non trouvé").encode());
return;
}
context.response()
.putHeader("content-type","application/json: charset=UTF-8")
.end(new JsonObject().put("success", "L'utilisateur à bien été supprimé").encode());
return;
});
}
context.response()
.putHeader("content-type", "application/json: charset=UTF-8")
.end(new JsonObject().put("success", "L'utilisateur à bien été supprimé").encode());
return;
});
}
}

View File

@ -9,7 +9,7 @@ import Objet from "./pages/Gestion/Objet.jsx";
import AddObject from "./pages/Gestion/AddObject.jsx";
import Signup from "./pages/Signup.jsx";
import Login from "./pages/Login.jsx";
import Settings from "./pages/Settings.jsx";
import Profil from "./pages/Profil.jsx";
import Sidebar from "./pages/Admin/sidebar.jsx";
import User from "./pages/Admin/User.jsx";
import Dashboard from "./pages/Admin/Dashboard.jsx";
@ -31,9 +31,9 @@ function App() {
<Route path="/signup" element={<Signup />} />
<Route path="/login" element={<Login />} />
<Route path="/ajouterObjet" element={<ProtectedRoute element={<AddObject />} />} />
<Route path="/settings" element={<Settings />} />
<Route path="/profil" element={<ProtectedRoute element={<Profil />}/>} />
<Route path="/sidebar" element={<Sidebar />} />
<Route path="/user" element={<User />} />
<Route path="/user" element={<ProtectedRoute element={<User />}/>} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/adminobjet" element={<ProtectedRoute element={<AdminObjet />} />} />
</Routes>

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
import { X, Menu, LogIn, UserPlus, LogOut, Settings } from "lucide-react";
import { X, Menu, LogIn, UserPlus, LogOut, User } from "lucide-react";
import { Link } from "react-router-dom";
import { useAuth } from "../AuthContext";
@ -80,12 +80,12 @@ function Header() {
<>
<li className="sm:hidden">
<Link
to="/settings"
to="/profil"
onClick={()=>setIsMenuOpen(false)}
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
>
<Settings size={20} />
<span>Paramètres</span>
<User size={20} />
<span>Profil</span>
<span></span>
</Link>
</li>
@ -127,11 +127,11 @@ function Header() {
) : (
<div className="hidden sm:flex gap-4">
<Link
to="/settings"
to="/profil"
onClick={()=>setIsMenuOpen(false)}
className="flex items-center gap-2 text-gray-600 hover:text-indigo-600"
>
<Settings size={20} />
<User size={20} />
<span></span>
</Link>
<button

View File

@ -9,7 +9,6 @@ import {
UserPlus,
RadioTower,
Binoculars,
Settings,
BadgePlus,
} from "lucide-react";
function Gestion() {

View File

@ -1,7 +1,7 @@
import React, { useState } from "react";
import { Mail, Lock } from "lucide-react";
import { Mail, Lock, AlertCircle } from "lucide-react";
import { useNavigate, Link } from "react-router-dom";
import axios from "axios"; // Assurez-vous d'avoir axios importé
import axios from "axios";
import { useAuth } from "../AuthContext";
import { API_BASE_URL } from "../config";
@ -10,6 +10,7 @@ function Login() {
email: "",
password: "",
});
const [error, setError] = useState("");
const { login } = useAuth(); // Utilisation du hook useAuth pour accéder à la fonction login
const navigate = useNavigate(); // Initialisation de useNavigate
@ -19,43 +20,72 @@ function Login() {
...prev,
[name]: value,
}));
// Réinitialiser l'erreur lorsque l'utilisateur commence à modifier le formulaire
if (error) setError("");
};
const handleSubmit = async (e) => {
e.preventDefault();
setError(""); // Réinitialiser les erreurs à chaque tentative
try {
const response = await fetch(`${API_BASE_URL}/login`, {
method: "POST",
const response = await axios.post(`${API_BASE_URL}/login`, formData, {
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(formData),
});
const data = response.data;
// Récupérer les données JSON de la réponse
const data = await response.json();
// Vérifiez que la réponse contient bien un token
if (data.token) {
// Appel de la fonction login du contexte pour stocker le token
login(data.token);
// Rediriger vers la page d'accueil après la connexion
navigate("/");
} else {
console.error("Token manquant dans la réponse");
setError("Authentification échouée : token manquant dans la réponse");
}
} catch (error) {
console.error("Erreur lors de la connexion", error);
if (error.response) {
// Le serveur a répondu avec un statut d'erreur (4xx, 5xx)
if (error.response.status === 401) {
setError("Email ou mot de passe incorrect");
} else if (error.response.status === 422) {
setError("Données de formulaire invalides");
} else if (error.response.status >= 500) {
setError("Erreur serveur. Veuillez réessayer plus tard.");
} else {
setError(
error.response.data.message ||
"Une erreur s'est produite lors de la connexion"
);
}
} else if (error.request) {
// La requête a été faite mais pas de réponse reçue
setError(
"Impossible de joindre le serveur. Vérifiez votre connexion internet."
);
} else {
// Une erreur s'est produite lors de la configuration de la requête
setError("Une erreur s'est produite. Veuillez réessayer.");
}
}
};
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 py-12 px-4 sm:px-6 lg:px-8">
<div className="md:w-96 w-full bg-white rounded-lg shadow-md p-6 mx-auto">
<h2 className="text-2xl font-bold text-gray-800 mb-6 text-center">
Connexion
</h2>
{/* Message d'erreur */}
{error && (
<div className="mb-4 p-3 bg-red-50 border border-red-200 text-red-700 rounded-md flex items-start">
<AlertCircle className="h-5 w-5 mr-2 mt-0.5 flex-shrink-0" />
<span className="text-sm">{error}</span>
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
{/* Email */}
<div>
@ -94,6 +124,7 @@ function Login() {
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
minLength="8"
autoComplete="current-password"
/>
</div>
</div>

View File

@ -0,0 +1,317 @@
import React, { useState, useEffect } from 'react';
import { Mail, User, Lock, Edit, Save } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { API_BASE_URL } from "../config";
import axios from "axios";
function Profil() {
const [userData, setUserData] = useState({});
const identifiant=4;
const [formData, setFormData] = useState({
oldPassword: '',
newPassword: '',
confirmPassword: ''
});
const [editMode, setEditMode] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [successMessage, setSuccessMessage] = useState('');
const navigate = useNavigate();
useEffect(() => {
axios
.post(`${API_BASE_URL}/user`, {
id: identifiant,
})
.then((response) => {
setUserData(response.data);
console.log("Infos récupérées :", response.data);
})
.catch((error) => {
console.error("Erreur lors de la récupération :", error);
});
}, []);
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleProfileChange = (e) => {
const { name, value } = e.target;
setUserData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
setErrorMessage('');
setSuccessMessage('');
if (formData.newPassword !== formData.confirmPassword) {
setErrorMessage("Les nouveaux mots de passe ne correspondent pas !");
return;
}
try {
axios
.post(`${API_BASE_URL}/changePassword`, {
id: userData.id, // Il faudrait s'assurer que userData contient l'ID de l'utilisateur
oldPassword: formData.oldPassword,
newPassword: formData.newPassword
})
.then((response) => {
console.log("Modification du mot de passe réussie :", response.data);
setSuccessMessage("Mot de passe modifié avec succès !");
setFormData({
oldPassword: '',
newPassword: '',
confirmPassword: ''
});
})
.catch((error) => {
console.error("Erreur lors de la modification du mot de passe :", error);
setErrorMessage(error.response?.data?.error || "Une erreur est survenue");
});
setSuccessMessage("Mot de passe modifié avec succès !");
setFormData({
oldPassword: '',
newPassword: '',
confirmPassword: ''
});
} catch (error) {
setErrorMessage(error.message || "Une erreur est survenue");
}
};
const handleProfileSubmit = async (e) => {
e.preventDefault();
setErrorMessage('');
setSuccessMessage('');
axios
.post(`${API_BASE_URL}/updateProfil`, {
id: userData.id,
name: userData.name,
surname: userData.surname,
pseudo:userData.pseudo,
email: userData.email
})
.catch((error) => {
console.error("Erreur lors de la mise à jour du profil :", error);
setErrorMessage(error.response?.data?.error || "Une erreur est survenue");
})
.then((response) => {
console.log("Mise à jour du profil réussie :", response.data);
setSuccessMessage("Profil mis à jour avec succès !");
setEditMode(false);
});
};
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl mx-auto">
<h1 className="text-3xl font-bold text-gray-900 mb-8 text-center">Mon Profil</h1>
{errorMessage && (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4">
{errorMessage}
</div>
)}
{successMessage && (
<div className="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4">
{successMessage}
</div>
)}
<div className="grid md:grid-cols-2 gap-8">
{/* Informations du profil */}
<div className="bg-white rounded-lg shadow-md p-6">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-semibold text-gray-800">Informations Personnelles</h2>
<button
onClick={() => setEditMode(!editMode)}
className="text-indigo-600 hover:text-indigo-800"
>
{editMode ? <Save className="h-5 w-5" /> : <Edit className="h-5 w-5" />}
</button>
</div>
<form onSubmit={handleProfileSubmit} className="space-y-4">
<div className="flex items-center space-x-4 mb-4">
<div className="w-20 h-20 bg-indigo-100 rounded-full flex items-center justify-center">
<User className="h-10 w-10 text-indigo-600" />
</div>
<div>
<h3 className="text-lg font-medium">{userData.name} {userData.surname} ({userData.pseudo})</h3>
<p className="text-gray-500">{userData.email}</p>
</div>
</div>
<div className="bg-indigo-50 p-3 rounded-lg mb-4">
<p className="text-sm text-gray-700">Points de fidélité: <span className="font-semibold">{userData.points}</span> ({userData.role})</p>
</div>
{editMode ? (
<>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Prénom:</label>
<input
type="text"
name="name"
value={userData.name}
onChange={handleProfileChange}
className="block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Nom:</label>
<input
type="text"
name="surname"
value={userData.surname}
onChange={handleProfileChange}
className="block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Pseudo:</label>
<input
type="text"
name="pseudo"
value={userData.pseudo}
onChange={handleProfileChange}
className="block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">Email:</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Mail className="h-5 w-5 text-gray-400" />
</div>
<input
type="email"
name="email"
value={userData.email}
disabled
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
/>
</div>
</div>
<button
type="submit"
className="w-full flex justify-center py-2 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Sauvegarder
</button>
</>
) : (
<div className="space-y-3">
<div>
<p className="text-sm font-medium text-gray-500">Prénom</p>
<p className="mt-1">{userData.name}</p>
</div>
<div>
<p className="text-sm font-medium text-gray-500">Nom</p>
<p className="mt-1">{userData.surname}</p>
</div>
<div>
<p className="text-sm font-medium text-gray-500">Email</p>
<p className="mt-1">{userData.email}</p>
</div>
</div>
)}
</form>
</div>
{/* Changement de mot de passe */}
<div className="bg-white rounded-lg shadow-md p-6">
<h2 className="text-xl font-semibold text-gray-800 mb-4">Modifier le mot de passe</h2>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Mot de passe actuel:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Lock className="h-5 w-5 text-gray-400" />
</div>
<input
type="password"
name="oldPassword"
value={formData.oldPassword}
onChange={handleChange}
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
minLength="8"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Nouveau mot de passe:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Lock className="h-5 w-5 text-gray-400" />
</div>
<input
type="password"
name="newPassword"
value={formData.newPassword}
onChange={handleChange}
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
minLength="8"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Confirmer le nouveau mot de passe:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Lock className="h-5 w-5 text-gray-400" />
</div>
<input
type="password"
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleChange}
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
minLength="8"
/>
</div>
</div>
<button
type="submit"
className="w-full flex justify-center py-2.5 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Modifier le mot de passe
</button>
</form>
</div>
</div>
</div>
</div>
);
}
export default Profil;

View File

@ -1,161 +0,0 @@
import React, { useState } from 'react';
import { Mail, User, Lock } from 'lucide-react';
import { useNavigate, Link} from 'react-router-dom'; // Importation du hook useNavigate
function Settings() {
const [formData, setFormData] = useState({
name: '',
surname: '',
email: '',
gender: '',
password: '',
confirmPassword: ''
});
const navigate = useNavigate(); // Initialisation de useNavigate
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
if (formData.password !== formData.confirmPassword) {
alert("Les mots de passe ne correspondent pas !");
return;
}
try {
const response = await fetch(`${API_BASE_URL}/settings`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(formData),
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || "Erreur lors de la modification");
}
alert("Modification réussie !");
// Redirection vers la page d'accueil après une inscription réussie
navigate("/home"); // Remplace "/home" par l'URL de ta page d'accueil
} catch (error) {
alert(error.message);
}
};
return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 to-indigo-50 py-12 px-4 sm:px-6 lg:px-8">
<div className="w-96 bg-white rounded-lg shadow-md p-6 mx-auto">
<h2 className="text-2xl font-bold text-gray-800 mb-6 text-center">Settings</h2>
<form onSubmit={handleSubmit} className="space-y-4">
{/* (Formulaire changement Email, Mot de passe) */}
{/* Email */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Modifier votre email:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Mail className="h-5 w-5 text-gray-400" />
</div>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
/>
</div>
</div>
{/* Mot de passe */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Ancien mot de passe:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Lock className="h-5 w-5 text-gray-400" />
</div>
<input
type="password"
name="password"
value={formData.password}
onChange={handleChange}
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
minLength="8"
/>
</div>
</div>
{/* nouveau mot de passe */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Nouveau mot de passe:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Lock className="h-5 w-5 text-gray-400" />
</div>
<input
type="password"
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleChange}
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
minLength="8"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Confirmer le nouveau mot de passe:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<Lock className="h-5 w-5 text-gray-400" />
</div>
<input
type="password"
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleChange}
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
minLength="8"
/>
</div>
</div>
{/* Bouton d'inscription */}
<div className="pt-4">
<button
type="submit"
className="w-full flex justify-center py-2.5 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
Sauvegarder
</button>
</div>
</form>
</div>
</div>
);
}
export default Settings;

View File

@ -7,6 +7,7 @@ function Signup() {
const [formData, setFormData] = useState({
name: '',
surname: '',
pseudo:'',
email: '',
gender: '',
password: '',
@ -62,7 +63,7 @@ function Signup() {
{/* Formulaire (Nom, Prénom, Sexe, Email, Mot de passe) */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Nom:
Prénom:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
@ -81,7 +82,7 @@ function Signup() {
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Prénom:
Nom:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
@ -98,6 +99,25 @@ function Signup() {
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Pseudo:
</label>
<div className="relative">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<User className="h-5 w-5 text-gray-400" />
</div>
<input
type="text"
name="pseudo"
value={formData.pseudo}
onChange={handleChange}
className="pl-10 block w-full rounded-lg border-gray-300 border p-2.5 focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
required
/>
</div>
</div>
{/* Sexe */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">