diff --git a/src/App.jsx b/src/App.jsx index 092f6a5..0d42d00 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -7,6 +7,7 @@ import HomePage from "./views/HomePage"; import ShareAProject from "./views/ShareAProject"; import ExploreProjects from "./views/ExploreProjects"; import PrivateRoute from "./views/PrivateRoute"; +import ResetPasswords from "./components/ResetPassword"; import AboutUs from "./views/AboutUsPage"; const URL = "http://localhost:8000/api/v1/"; @@ -35,6 +36,7 @@ function App() { } /> } /> + } /> } /> {message}} /> diff --git a/src/components/ResetPassword.jsx b/src/components/ResetPassword.jsx new file mode 100644 index 0000000..ab44419 --- /dev/null +++ b/src/components/ResetPassword.jsx @@ -0,0 +1,200 @@ +import React, { useState } from "react"; +import { VStack, Box, Stack, Button, Text, Group } from "@chakra-ui/react"; +import { PasswordInput } from "./ui/password-input"; +import { Field } from "./ui/field"; +import { Toaster, toaster } from "../components/ui/toaster"; +import { Alert } from "../components/ui/alert"; +import { useNavigate } from "react-router-dom"; +import "../styles/ResetPassword.css"; + +const ResetPassword = () => { + const [loading, setLoading] = useState(false); + const [message, setMessage] = useState(""); + const navigate = useNavigate(); + const token = new URLSearchParams(window.location.search).get("token"); + const [errorMessage, setErrorMessage] = useState(""); + const [userData, setUserData] = useState({ + password_hash: "", + confirmPassword: "", + }); + const [errors, setErrors] = useState({ + password_hash: false, + confirmPassword: false, + }); + const handleChange = (e) => { + const { name, value } = e.target; + setUserData((prevData) => ({ + ...prevData, + [name]: value, + })); + + // Clear error message on input change + if (name === "password_hash" || name === "confirmPassword") { + setErrorMessage(""); + } + }; + const handleBlur = (e) => { + const { name, value } = e.target; + // Clear the error if the input is not empty + if (value.trim()) { + setErrors((prevErrors) => ({ + ...prevErrors, + [name]: false, + })); + } + }; + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + setMessage(""); + // check if all fields are filled + const { password_hash, confirmPassword } = userData; + const newErrors = { + password_hash: !password_hash, + confirmPassword: !confirmPassword, + }; + setErrors(newErrors); + + // Check if passwords match + if (password_hash !== confirmPassword) { + setErrors((prevErrors) => ({ + ...prevErrors, + confirmPassword: true, + })); + setErrorMessage("Passwords do not match!"); + setLoading(false); + return; + } + // If any field is missing, prevent user form submission + if (Object.values(newErrors).some((error) => error)) { + setLoading(false); + setMessage("all field is required"); + return; + } + try { + console.log(token); + console.log(userData.password_hash); + const response = await fetch( + `http://localhost:8001/api/v1/reset-password/${token}`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ password: userData.password_hash }), + } + ); + + if (response.ok) { + setMessage( + "Password reset successful, You can now login using the correct credentials!" + ); + toaster.create({ + title: "Password reset", + description: message, + type: "success", + duration: 4000, + action: { + label: "x", + }, + }); + navigate("/Home"); + } else { + const errorData = await response.json(); + setMessage(errorData.message || "Error resetting password."); + console.error("Error resetting password"); + toaster.create({ + title: "Error resetting password", + description: message, + type: "error", + action: { + label: "x", + }, + }); + } + } catch (error) { + setMessage("An unexpected error occurred."); + console.error("An unexpected error occurred."); + toaster.create({ + title: "An unexpected error occurred.", + type: "error", + action: { + label: "x", + }, + }); + } finally { + setLoading(false); + } + }; + + return ( + <> + + + + + Reset Password + + + + + + + + + + + {errorMessage && ( + + + + )} + {/* Display error message */} + + + + {loading ? "Resetting..." : "Reset Password"} + + + + + + + + > + ); +}; + +export default ResetPassword; diff --git a/src/styles/ResetPassword.css b/src/styles/ResetPassword.css new file mode 100644 index 0000000..8c0db90 --- /dev/null +++ b/src/styles/ResetPassword.css @@ -0,0 +1,44 @@ +.reset-password-container { + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +.reset-password-container h2 { + margin-bottom: 20px; + font-size: 1.5rem; +} + +.reset-password-container form { + display: flex; + flex-direction: column; + width: 100%; +} + +.reset-password-container input { + margin-bottom: 15px; + padding: 10px; + font-size: 1rem; + border: 1px solid #ccc; + border-radius: 4px; +} + +.reset-password-container button { + padding: 10px; + font-size: 1rem; + color: white; + background-color: #007bff; + border: none; + border-radius: 4px; + cursor: pointer; +} + +.reset-password-container button:disabled { + background-color: #ccc; + cursor: not-allowed; +} + +.reset-password-container p { + margin-top: 10px; + color: green; +} diff --git a/src/views/HomePage.jsx b/src/views/HomePage.jsx index 72ad9db..95e2e99 100644 --- a/src/views/HomePage.jsx +++ b/src/views/HomePage.jsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState, useEffect } from "react"; import { Input } from "@chakra-ui/react"; import { Field } from "../components/ui/field"; import { Button } from "../components/ui/button"; @@ -7,6 +7,11 @@ import { useNavigate } from "react-router-dom"; import { Toaster, toaster } from "../components/ui/toaster"; const HomePage = () => { const storedAuth = JSON.parse(localStorage.getItem("auth")); + const [databoard, setDataboard] = useState({ + projects: 0, + users: 0, + comments: 0, + }); const navigate = useNavigate(); const handleAuthentificationCheck = () => { @@ -26,6 +31,33 @@ const HomePage = () => { } }; + useEffect(() => { + // Fetch data from JSON Server + const fetchDashboardData = async () => { + try { + //const response = await fetch("http://localhost:8001/api/v1/dashboard"); + const url = "http://localhost:8001/api/v1/dashboard"; + //const token = JSON.parse(localStorage.getItem("auth")); + const response = await fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + //Authorization: `Bearer ${token}`, // Include the token in the Authorization header + }, + }); + if (response.ok) { + const dashboardData = await response.json(); + setDataboard(dashboardData.data); + } else { + console.error("Failed to get dashboard data from the db"); + } + } catch (error) { + console.error("Error get dashboard data:", error); + } + }; + + fetchDashboardData(); + }, []); // Run only once when the component mounts return ( @@ -69,9 +101,9 @@ const HomePage = () => { next level. - PROJECTS SHARED: 1,024+ - REVIEWS GIVEN: 5,678+ - ACTIVE STUDENTS: 856+ + PROJECTS SHARED: {databoard.projects} + REVIEWS GIVEN: {databoard.comments} + ACTIVE STUDENTS: {databoard.users}
PROJECTS SHARED: 1,024+
REVIEWS GIVEN: 5,678+
ACTIVE STUDENTS: 856+
PROJECTS SHARED: {databoard.projects}
REVIEWS GIVEN: {databoard.comments}
ACTIVE STUDENTS: {databoard.users}