diff --git a/SerpentRace_Frontend/src/App.jsx b/SerpentRace_Frontend/src/App.jsx index 0314253e..7ed485e4 100644 --- a/SerpentRace_Frontend/src/App.jsx +++ b/SerpentRace_Frontend/src/App.jsx @@ -16,6 +16,9 @@ import ScrollToTop from "./components/ScrollToTop" import GameScreen from "./pages/Game/GameScreen" import Reports from "./pages/Report/Reports" import Lobby from "./pages/Lobby/Lobby" +import { ToastConfig } from "./components/Toastify/toastifyServices" // ✅ fontos: named import, nem default! + + function App() { const [isMobile, setIsMobile] = useState(false) @@ -44,28 +47,31 @@ function App() { // } return ( - - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + <> + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + - {/* Add more routes as needed */} - - + {/* ✅ Toastify Container */} + + ) } diff --git a/SerpentRace_Frontend/src/components/DeckCreator/CardEditor.jsx b/SerpentRace_Frontend/src/components/DeckCreator/CardEditor.jsx index 2f48e046..8fb712f7 100644 --- a/SerpentRace_Frontend/src/components/DeckCreator/CardEditor.jsx +++ b/SerpentRace_Frontend/src/components/DeckCreator/CardEditor.jsx @@ -7,6 +7,8 @@ import TaskCardEditor from "./TaskCardEditor.jsx" import JokerCardEditor from "./JokerCardEditor.jsx" import LuckCardEditor from "./LuckCardEditor.jsx" import CardPreview from "./CardPreview.jsx" +import { notifySuccess, notifyError,notifyWarning } from "../../components/Toastify/toastifyServices" + export default function CardEditor({ card, isCreating, cardType, onSave, onCancel }) { const [cardData, setCardData] = useState(null) @@ -65,33 +67,24 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance } }, [card, isCreating, cardType]) - const handleSave = () => { - if (!cardData) return - - // Validáció - if (!validateCard(cardData)) return - - onSave(cardData) - } - const validateCard = (data) => { if (data.type === 'task') { if (!data.question && !data.statement) { - alert("❌ Kérdés vagy állítás megadása kötelező!") + notifyError("Kérdés vagy állítás megadása kötelező!") return false } if (data.subType === 'quiz' && data.options.some(opt => !opt.trim())) { - alert("❌ Minden válaszlehetőséget ki kell tölteni!") + notifyError("Minden válaszlehetőséget ki kell tölteni!") return false } } else if (data.type === 'joker') { if (!data.text || !data.text.trim()) { - alert("❌ Joker kártya szövege nem lehet üres!") + notifyError("Joker kártya szövege nem lehet üres!") return false } } else if (data.type === 'luck') { if (!data.text || !data.text.trim()) { - alert("❌ Szerencse kártya szövege nem lehet üres!") + notifyError("Szerencse kártya szövege nem lehet üres!") return false } } @@ -103,6 +96,19 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance setCardData(prev => prev ? { ...prev, ...updates } : null) } + const handleSave = () => { + if (!cardData) return + + if (!validateCard(cardData)) return + + try { + onSave(cardData) + notifySuccess('Kártya sikeresen mentve!') + } catch (error) { + notifyError('Hiba történt a kártya mentése során: ' + (error?.message || String(error))) + } + } + // Ha nincs kiválasztott kártya vagy új kártya létrehozás if (!cardData) { return ( @@ -134,7 +140,7 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance

- {isCreating ? 'Új' : 'Szerkesztés'} {' '} + {isCreating ? 'Új' : 'Szerkesztés'}{' '} {cardData.type === 'task' && 'Feladat kártya'} {cardData.type === 'joker' && 'Joker kártya'} {cardData.type === 'luck' && 'Szerencse kártya'} @@ -157,8 +163,8 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance onClick={() => setShowPreview(!showPreview)} className={` flex items-center gap-2 px-4 py-2 rounded-xl font-medium transition-all duration-200 - ${showPreview - ? 'bg-[color:var(--color-success)] text-[color:var(--color-text-inverse)]' + ${showPreview + ? 'bg-[color:var(--color-success)] text-[color:var(--color-text-inverse)]' : 'bg-[color:var(--color-background)] text-[color:var(--color-text)] hover:bg-[color:var(--color-surface-selected)]' } `} @@ -168,12 +174,15 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance + onClick={() => { + notifyWarning('Kártya készítés megszakítva') + onCancel() + }} + className="flex items-center gap-2 px-4 py-2 rounded-xl bg-[color:var(--color-background)] hover:bg-[color:var(--color-surface-selected)] text-[color:var(--color-text)] transition-all duration-200" +> + + Mégse + - + {/* Dropdown Menu */}
- + - + + +
+

+ + )} + {/* Footer Stats */}
📊 Összesen: {cards.length} kártya
- + {cards.length > 0 && (
- 📋 {cards.filter(c => c.type === 'task').length} - 🃏 {cards.filter(c => c.type === 'joker').length} - 🎲 {cards.filter(c => c.type === 'luck').length} + 📋 {cards.filter((c) => c.type === "task").length} + 🃏 {cards.filter((c) => c.type === "joker").length} + 🎲 {cards.filter((c) => c.type === "luck").length}
)}
) -} \ No newline at end of file +} diff --git a/SerpentRace_Frontend/src/components/Landingpage/LandingPage.jsx b/SerpentRace_Frontend/src/components/Landingpage/LandingPage.jsx index f3be5e7e..1f37c884 100644 --- a/SerpentRace_Frontend/src/components/Landingpage/LandingPage.jsx +++ b/SerpentRace_Frontend/src/components/Landingpage/LandingPage.jsx @@ -63,7 +63,7 @@ const LandingPage = ({ onNavigateToPlay, onNavigateToAuth, onNavigateToGame }) = {/* If not authenticated show Login/Register; if authenticated show Home button */} {!auth ? ( <> - + diff --git a/SerpentRace_Frontend/src/components/Toastify/toastifyServices.jsx b/SerpentRace_Frontend/src/components/Toastify/toastifyServices.jsx new file mode 100644 index 00000000..518679ed --- /dev/null +++ b/SerpentRace_Frontend/src/components/Toastify/toastifyServices.jsx @@ -0,0 +1,165 @@ +import { toast, ToastContainer, Bounce } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; + +/** + * 🔧 Ezt csak egyszer kell betenni az App.jsx-be! + * = az a komponens, ami kirendereli a toastokat + */ +export const ToastConfig = () => ( + +); + +/** + * 🦄 Alapértelmezett toast üzenet (semleges) + * notify("Üzenet szövege") + */ +export const notify = (message) => { + toast(message, { + position: "bottom-right", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: false, + pauseOnHover: true, + draggable: true, + theme: "light", + transition: Bounce, + }); +}; + +/** + * ✅ Sikeres művelethez + * notifySuccess("Sikeres mentés!") + */ +export const notifySuccess = (message) => { + toast.success(message, { + position: "bottom-right", + autoClose: 4000, + theme: "light", + transition: Bounce, + }); +}; + +/** + * ❌ Hibás művelethez + * notifyError("Hiba történt a mentés során!") + */ +export const notifyError = (message) => { + toast.error(message, { + position: "bottom-right", + autoClose: 5000, + theme: "light", + transition: Bounce, + }); +}; + +/** + * ℹ️ Információs üzenethez + * notifyInfo("Friss adatok betöltve!") + */ +export const notifyInfo = (message) => { + toast.info(message, { + position: "bottom-right", + autoClose: 4000, + theme: "light", + transition: Bounce, + }); +}; + +/** + * ⚠️ Figyelmeztetéshez + * notifyWarning("Figyelem! Nem mentett módosítások vannak!") + */ +export const notifyWarning = (message) => { + toast.warn(message, { + position: "bottom-right", + autoClose: 4000, + theme: "light", + transition: Bounce, + }); +}; + + + + + +// import React, { useState } from "react"; +// import { notifyWarning } from "../../components/Toastify/toastifyServices"; + +// function AuthLogin() { +// const [email, setEmail] = useState(""); +// const [password, setPassword] = useState(""); + +// const handleLogin = async (e) => { +// e.preventDefault(); + +// // Példa jelszó ellenőrzés logikára: +// if (password !== "titkosjelszo123") { +// notifyWarning("⚠️ Hibás jelszó! Kérlek próbáld újra."); +// return; +// } + +// // Ha jó a jelszó: +// notifySuccess("✅ Sikeres bejelentkezés!"); +// }; + +// return ( +//
+// setEmail(e.target.value)} +// /> +// setPassword(e.target.value)} +// /> +// +//
+// ); +// } + +// export default AuthLogin; + + + +// meghivas +// import { toast } from "react-toastify"; + +// // 🔔 Alap toast +// export const notify = (msg) => toast(msg); + +// // ✅ Sikeres üzenet +// export const notifySuccess = (msg) => toast.success(msg); + +// // ⚠️ Figyelmeztetés +// export const notifyWarning = (msg) => toast.warning(msg); + +// // ❌ Hiba +// export const notifyError = (msg) => toast.error(msg); + +// // ℹ️ Információ +// export const notifyInfo = (msg) => toast.info(msg); + + + +// hasznalat +// import { notifyWarning } from "../../components/Toastify/toastifyServices"; + +// if (password !== "titkos") { +// notifyWarning("⚠️ Hibás jelszó!"); +// } diff --git a/SerpentRace_Frontend/src/pages/Auth/LoginForm.jsx b/SerpentRace_Frontend/src/pages/Auth/LoginForm.jsx index 6aa74060..308f76a0 100644 --- a/SerpentRace_Frontend/src/pages/Auth/LoginForm.jsx +++ b/SerpentRace_Frontend/src/pages/Auth/LoginForm.jsx @@ -1,12 +1,11 @@ // 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, useEffect } from "react" import { useLocation, useNavigate } from "react-router-dom" import { login } from "../../api/userApi" +import { FaArrowLeft } from "react-icons/fa" export default function LoginForm() { const [email, setEmail] = useState("") @@ -32,23 +31,23 @@ export default function LoginForm() { e.preventDefault() setError("") setShowErrorPopup(false) + if (!email || !password) { setError("Minden mező kitöltése kötelező.") setShowErrorPopup(true) setTimeout(() => setShowErrorPopup(false), 2000) return } + if (!validateEmail(email)) { setError("Hibás email formátum.") setShowErrorPopup(true) setTimeout(() => setShowErrorPopup(false), 2000) return } - // Backend API + login(email, password) .then((response) => { - console.log(response) - // Csak a response.status-t ellenőrizd! if (response && response.status === 200) { if (response.data && response.data.user) { localStorage.setItem("username", response.data.user.username) @@ -61,7 +60,7 @@ export default function LoginForm() { setTimeout(() => setShowErrorPopup(false), 2000) } }) - .catch((error) => { + .catch(() => { setError("Hibás bejelentkezési adatok.") setShowErrorPopup(true) setTimeout(() => setShowErrorPopup(false), 2000) @@ -75,18 +74,35 @@ export default function LoginForm() { animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.25 }} + className="relative flex flex-col items-center" > -

Bejelentkezés

+ {/* 🔙 Vissza nyíl gomb — most pontosan a fehér box bal felső sarkában */} +
navigate("/")} + > + + + Vissza a főoldalra + +
+ +

+ Bejelentkezés +

+ {showSuccess && (
Sikeres regisztráció! Az email ellenőrzése után be tudsz lépni.
)} + {showErrorPopup && error && (
{error}
)} +
setShowErrorPopup(false), 2000) } } catch (err) { - let msg = "Ismeretlen hiba történt." - if (err.response && err.response.data && err.response.data.error) { - msg = err.response.data.error - } else if (err.message) { - msg = err.message - } + let msg = err?.response?.data?.error || err.message || "Ismeretlen hiba történt." setError(msg) setShowErrorPopup(true) setTimeout(() => setShowErrorPopup(false), 2000) @@ -89,56 +79,37 @@ export default function RegisterForm() { animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.25 }} + className="relative flex flex-col items-center" > -

Regisztráció

+ {/* 🔙 Vissza nyíl gomb – ugyanott, mint a login oldalon */} +
navigate("/")} + > + + + Vissza a főoldalra + +
+ +

+ Regisztráció +

+ {showErrorPopup && error && (
{error}
)} + - setLastname(e.target.value)} - /> - setFirstname(e.target.value)} - /> - setUsername(e.target.value)} - /> - setEmail(e.target.value)} - /> - setPhone(e.target.value)} - /> - setPassword(e.target.value)} - /> - setConfirmPassword(e.target.value)} - /> + setLastname(e.target.value)} /> + setFirstname(e.target.value)} /> + setUsername(e.target.value)} /> + setEmail(e.target.value)} /> + setPhone(e.target.value)} /> + setPassword(e.target.value)} /> + setConfirmPassword(e.target.value)} />