diff --git a/SerpentRace_Frontend/src/api/userApi.js b/SerpentRace_Frontend/src/api/userApi.js index 80d99ca5..db92ba47 100644 --- a/SerpentRace_Frontend/src/api/userApi.js +++ b/SerpentRace_Frontend/src/api/userApi.js @@ -1,67 +1,75 @@ -import axios from 'axios'; - +import axios from "axios" export const API_CONFIG = { - baseURL: import.meta.env.VITE_API_URL+'/api', - wsURL: 'http://localhost:3000', + baseURL: import.meta.env.VITE_API_URL + "/api", + wsURL: "http://localhost:3000", timeout: 10000, - retryAttempts: 3 -}; + retryAttempts: 3, +} const apiClient = axios.create({ baseURL: API_CONFIG.baseURL, timeout: API_CONFIG.timeout, withCredentials: true, // Important for cookie-based auth headers: { - 'Content-Type': 'application/json' - } -}); - + "Content-Type": "application/json", + }, +}) // Add request interceptor for debugging apiClient.interceptors.request.use( (config) => { - console.log('Request URL:', config.url); - console.log('Request headers:', config.headers); - console.log('Current cookies:', document.cookie); - return config; + console.log("Request URL:", config.url) + console.log("Request headers:", config.headers) + console.log("Current cookies:", document.cookie) + return config }, (error) => { - return Promise.reject(error); + return Promise.reject(error) } -); +) // Add response interceptor for debugging cookies apiClient.interceptors.response.use( (response) => { - console.log('Response status:', response.status); - console.log('Response headers:', response.headers); - console.log('Set-Cookie headers:', response.headers['set-cookie']); - console.log('Cookies after response:', document.cookie); - return response; + console.log("Response status:", response.status) + console.log("Response headers:", response.headers) + console.log("Set-Cookie headers:", response.headers["set-cookie"]) + console.log("Cookies after response:", document.cookie) + return response }, (error) => { - console.error('API Error:', error.response?.data || error.message); - return Promise.reject(error); + console.error("API Error:", error.response?.data || error.message) + return Promise.reject(error) } -); +) //login export const login = async (username, password) => { - try { - const response = await apiClient.post('/users/login', { username, password }); - return response.data; - } catch (error) { - throw error; - } -}; + try { + const response = await apiClient.post("/users/login", { username, password }) + return response.data + } catch (error) { + throw error + } +} //register export const register = async (username, email, password, fname, lname, phone) => { - try { - const response = await apiClient.post('/users/create', { username, email, password, fname, lname, phone }); - return response.data; - } catch (error) { - throw error; - } -}; \ No newline at end of file + try { + const response = await apiClient.post("/users/create", { username, email, password, fname, lname, phone }) + return { ...response.data, status: response.status } + } catch (error) { + throw error + } +} + +//verify email +export const verifyEmail = async (token) => { + try { + const response = await apiClient.get(`/users/verify-email/${token}`) + return response.data + } catch (error) { + throw error + } +} diff --git a/SerpentRace_Frontend/src/pages/Auth/AuthCard.jsx b/SerpentRace_Frontend/src/pages/Auth/AuthCard.jsx index 520b4381..43278921 100644 --- a/SerpentRace_Frontend/src/pages/Auth/AuthCard.jsx +++ b/SerpentRace_Frontend/src/pages/Auth/AuthCard.jsx @@ -1,46 +1,44 @@ // src/pages/Auth/AuthLogin.jsx // Kártya amelyiken a bejelentkezés és regisztráció van -import { motion, AnimatePresence } from "framer-motion"; -import Animation from "../../assets/SerpentRace_Animation/SerpentRace_Animation"; -import LoginForm from "./LoginForm"; -import RegisterForm from "./RegisterForm"; -import Logo from "../../assets/pictures/Logo"; +import { motion, AnimatePresence } from "framer-motion" +import Animation from "../../assets/SerpentRace_Animation/SerpentRace_Animation" +import LoginForm from "./LoginForm" +import RegisterForm from "./RegisterForm" +import Logo from "../../assets/pictures/Logo" export default function AuthCard({ isRegistering, setIsRegistering }) { return ( {/* Bal oldali kép és szöveg */}
- +

- Lépj be és légy a legjobb! + Lépj be és légy a legjobb!

{/* Jobb oldali űrlap */}
- - {isRegistering ? : } - + {isRegistering ? : } setIsRegistering(!isRegistering)} > - {isRegistering - ? "Már van fiókod? Jelentkezz be itt!" - : "Nincs még fiókod? Regisztrálj itt!"} + {isRegistering ? "Már van fiókod? Jelentkezz be itt!" : "Nincs még fiókod? Regisztrálj itt!"}
- ); + ) } diff --git a/SerpentRace_Frontend/src/pages/Auth/EmailVerification.jsx b/SerpentRace_Frontend/src/pages/Auth/EmailVerification.jsx index 1a018745..5566eadc 100644 --- a/SerpentRace_Frontend/src/pages/Auth/EmailVerification.jsx +++ b/SerpentRace_Frontend/src/pages/Auth/EmailVerification.jsx @@ -1,58 +1,94 @@ // src/pages/Auth/EmailVerification.jsx // Rublikák a kód beírásához, email ellenőrzéshez -import { useState, useRef } from "react"; -import Background from "../../assets/backgrounds/Background"; -import { motion } from "framer-motion"; -import Button from "../../components/Buttons/Button"; - +import { useState, useRef, useEffect } from "react" +import Background from "../../assets/backgrounds/Background" +import { motion } from "framer-motion" +import Button from "../../components/Buttons/Button" +import { useLocation } from "react-router-dom" export default function EmailVerification() { - const [code, setCode] = useState(Array(6).fill("")); - const inputRefs = useRef([]); + const [code, setCode] = useState(Array(6).fill("")) + const inputRefs = useRef([]) + const location = useLocation() + const [showSuccess, setShowSuccess] = useState(false) + const [error, setError] = useState("") + + useEffect(() => { + if (location.state && location.state.success) { + setShowSuccess(true) + setTimeout(() => setShowSuccess(false), 1500) + } + }, [location.state]) const handleChange = (e, index) => { - const { value } = e.target; + const { value } = e.target if (/^\d*$/.test(value) && value.length <= 1) { - const newCode = [...code]; - newCode[index] = value; - setCode(newCode); + const newCode = [...code] + newCode[index] = value + setCode(newCode) if (value && index < 5) { - inputRefs.current[index + 1].focus(); + inputRefs.current[index + 1].focus() } } - }; + } const handleKeyDown = (e, index) => { if (e.key === "Backspace" && !code[index] && index > 0) { - inputRefs.current[index - 1].focus(); + inputRefs.current[index - 1].focus() } else if (e.key === "ArrowLeft" && index > 0) { - inputRefs.current[index - 1].focus(); + inputRefs.current[index - 1].focus() } else if (e.key === "ArrowRight" && index < 5) { - inputRefs.current[index + 1].focus(); + inputRefs.current[index + 1].focus() } else if (/^\d$/.test(e.key) && code[index]) { - e.preventDefault(); - const newCode = [...code]; - newCode[index] = e.key; - setCode(newCode); - + e.preventDefault() + const newCode = [...code] + newCode[index] = e.key + setCode(newCode) + if (index < 5) { setTimeout(() => { - inputRefs.current[index + 1].focus(); - }, 0); + inputRefs.current[index + 1].focus() + }, 0) } } - }; + } - const handleSubmit = (e) => { - e.preventDefault(); - console.log("Kód:", code.join("")); - // Backend API - }; + const handleSubmit = async (e) => { + e.preventDefault() + setError("") + const token = code.join("") + if (token.length !== 6) { + setError("A kód 6 számjegyből áll.") + return + } + try { + const res = await fetch(`/verify-email/${token}`) + const data = await res.json() + if (data.success) { + setShowSuccess(true) + setTimeout(() => setShowSuccess(false), 2000) + } else { + setError(data.message || "Sikertelen ellenőrzés.") + } + } catch (err) { + setError("Hiba történt az ellenőrzés során.") + } + } return (
+ {showSuccess && ( +
+ Sikeres email ellenőrzés! +
+ )} + {error && ( +
+ {error} +
+ )} handleChange(e, index)} onKeyDown={(e) => handleKeyDown(e, index)} ref={(el) => (inputRefs.current[index] = el)} - className={`w-12 h-12 px-2 py-3 border rounded-lg focus:ring-4 focus:ring-indigo-400 text-gray-700 placeholder-gray-400 bg-gray-50 text-center text-2xl tracking-widest ${!digit ? 'placeholder-opacity-100' : 'placeholder-opacity-0'}`} + className={`w-12 h-12 px-2 py-3 border rounded-lg focus:ring-4 focus:ring-indigo-400 text-gray-700 placeholder-gray-400 bg-gray-50 text-center text-2xl tracking-widest ${ + !digit ? "placeholder-opacity-100" : "placeholder-opacity-0" + }`} // nem tudom, hogy hogyan jobb // placeholder="_" maxLength="1" @@ -85,5 +123,5 @@ export default function EmailVerification() {
- ); -} \ No newline at end of file + ) +} diff --git a/SerpentRace_Frontend/src/pages/Auth/LoginForm.jsx b/SerpentRace_Frontend/src/pages/Auth/LoginForm.jsx index 5d5df321..f06de31c 100644 --- a/SerpentRace_Frontend/src/pages/Auth/LoginForm.jsx +++ b/SerpentRace_Frontend/src/pages/Auth/LoginForm.jsx @@ -1,42 +1,52 @@ // src/pages/Auth/LoginForm.jsx // Bejelentkezési űrlap -import InputBox from "../../components/Inputs/InputBox"; -import Button from "../../components/Buttons/Button"; -import { motion } from "framer-motion"; -import { useState } from "react"; -import { login } from "../../api/userApi"; +import InputBox from "../../components/Inputs/InputBox" +import Button from "../../components/Buttons/Button" +import { motion } from "framer-motion" +import { useState, useEffect } from "react" +import { useLocation } from "react-router-dom" +import { login } from "../../api/userApi" export default function LoginForm() { - const [email, setEmail] = useState(""); - const [password, setPassword] = useState(""); - const [error, setError] = useState(""); + const [email, setEmail] = useState("") + const [password, setPassword] = useState("") + const [error, setError] = useState("") + const location = useLocation() + const [showSuccess, setShowSuccess] = useState(false) + + useEffect(() => { + if (location.state && location.state.success) { + setShowSuccess(true) + setTimeout(() => setShowSuccess(false), 4000) + } + }, [location.state]) function validateEmail(email) { - return /\S+@\S+\.\S+/.test(email); + return /\S+@\S+\.\S+/.test(email) } const handleSubmit = (e) => { - e.preventDefault(); - setError(""); + e.preventDefault() + setError("") if (!email || !password) { - setError("Minden mező kitöltése kötelező."); - return; + setError("Minden mező kitöltése kötelező.") + return } if (!validateEmail(email)) { - setError("Hibás email formátum."); - return; + setError("Hibás email formátum.") + return } // Backend API login(email, password) .then((data) => { - console.log(data); - console.log("Bejelentkezés:", { email, password }); + console.log(data) + console.log("Bejelentkezés:", { email, password }) }) .catch((error) => { - setError("Hibás bejelentkezési adatok."); - }); - }; + setError("Hibás bejelentkezési adatok.") + }) + } return (

Bejelentkezés

- {error && ( -
{error}
+ {showSuccess && ( +
+ Sikeres regisztráció! Az email ellenőrzése után be tudsz lépni. +
)} + {error &&
{error}
}
setEmail(e.target.value)} + onChange={(e) => setEmail(e.target.value)} /> setPassword(e.target.value)} + onChange={(e) => setPassword(e.target.value)} />