From 5d83588470c1968ad5d022cfead906d2fb45757d Mon Sep 17 00:00:00 2001 From: WalkeU Date: Mon, 3 Nov 2025 18:55:37 +0100 Subject: [PATCH] start nincs --- SerpentRace_Frontend/src/App.jsx | 6 +- .../src/components/Landingpage/PlayMenu.jsx | 19 +- .../src/pages/Game/ChooseDeck.jsx | 362 ++++++++++++++++++ .../src/pages/{Lobby => Game}/Lobby.jsx | 5 +- .../src/pages/Game/PlayerSetup.jsx | 135 +++++++ 5 files changed, 522 insertions(+), 5 deletions(-) create mode 100644 SerpentRace_Frontend/src/pages/Game/ChooseDeck.jsx rename SerpentRace_Frontend/src/pages/{Lobby => Game}/Lobby.jsx (96%) create mode 100644 SerpentRace_Frontend/src/pages/Game/PlayerSetup.jsx diff --git a/SerpentRace_Frontend/src/App.jsx b/SerpentRace_Frontend/src/App.jsx index 80aa0a79..e9a42897 100644 --- a/SerpentRace_Frontend/src/App.jsx +++ b/SerpentRace_Frontend/src/App.jsx @@ -14,10 +14,12 @@ import About from "./pages/About/About" import ScrollToTop from "./components/ScrollToTop" import GameScreen from "./pages/Game/GameScreen" import Reports from "./pages/Report/Reports" -import Lobby from "./pages/Lobby/Lobby" +import Lobby from "./pages/Game/Lobby" import ProfileCard from "./components/Userdetails/Userdetails" import { ToastConfig } from "./components/Toastify/toastifyServices" // ✅ fontos: named import, nem default! import VerifyEmailPage from "./pages/Auth/VerifyEmailPage" +import ChooseDeck from "./pages/Game/ChooseDeck" +import PlayerSetup from "./pages/Game/PlayerSetup" function App() { const [isMobile, setIsMobile] = useState(false) @@ -66,6 +68,8 @@ function App() { } /> {/* } /> */} } /> + } /> + } /> diff --git a/SerpentRace_Frontend/src/components/Landingpage/PlayMenu.jsx b/SerpentRace_Frontend/src/components/Landingpage/PlayMenu.jsx index 72cbe2eb..4a26513e 100644 --- a/SerpentRace_Frontend/src/components/Landingpage/PlayMenu.jsx +++ b/SerpentRace_Frontend/src/components/Landingpage/PlayMenu.jsx @@ -1,4 +1,5 @@ import React, { useState } from "react" +import { useNavigate } from "react-router-dom" import LogoCard from "../../assets/pictures/LogoCard.jsx" import logoImg from "../../assets/pictures/Logo.png" // <-- EZT ADD HOZZÁ import ButtonDark from "../Buttons/ButtonDark.jsx" @@ -12,6 +13,7 @@ const PlayMenu = ({ onJoinGame, onCreateGame, user, setUser }) => { // gyors username kiolvasás (ha a parent objektum user={ { name: ... } } küldi) const username = user?.name ?? null + const navigate = useNavigate() const handleJoin = () => { if (!joinCode.trim()) { @@ -23,7 +25,22 @@ const PlayMenu = ({ onJoinGame, onCreateGame, user, setUser }) => { } const handleCreate = () => { - onCreateGame() + // determine the name we will pass: logged in username or guestName + const nameToSend = username ?? guestName?.trim() + + if (!nameToSend) { + setGuestError("Adj meg egy nevet, vagy jelentkezz be!") + return + } + + // if parent provided a setter, set guest as current user (optional) + if (!username && setUser) { + setUser({ name: nameToSend }) + } + + // Do NOT call onCreateGame here to avoid any alert side-effects from parent. + // Just navigate to choose deck and pass username via location.state + navigate("/choosedeck", { state: { username: nameToSend } }) } // egyszerű segéd a kezdobetűk kinyerésére diff --git a/SerpentRace_Frontend/src/pages/Game/ChooseDeck.jsx b/SerpentRace_Frontend/src/pages/Game/ChooseDeck.jsx new file mode 100644 index 00000000..8aa4a9dd --- /dev/null +++ b/SerpentRace_Frontend/src/pages/Game/ChooseDeck.jsx @@ -0,0 +1,362 @@ +import React, { useEffect, useState } from "react" +import { useNavigate, useLocation } from "react-router-dom" +import Navbar from "../../components/Navbar/Navbar.jsx" +import Background from "../../assets/backgrounds/Background.jsx" +import Footer from "../../components/Footer/Footer.jsx" +import useRequireAuth from "../../hooks/useRequireAuth.jsx" +import ButtonGreen from "../../components/Buttons/ButtonGreen.jsx" +import { + FaFilter, + FaCalendarAlt, + FaArrowUp, + FaArrowDown, + FaSortAlphaDown, + FaSortAlphaUp, + FaQuestionCircle, + FaCheckCircle, + FaCircle, +} from "react-icons/fa" +import SearchBox from "../../components/Search/SearchBox.jsx" +import PopUp from "../../components/PopUp/PopUp.jsx" +import { motion } from "framer-motion" + +const deckTypes = [ + { label: "Luck", color: "var(--color-luck)" }, + { label: "Question", color: "var(--color-question)" }, + { label: "Joker", color: "var(--color-fun)" }, +] + +const origins = ["Mind", "Vállalati", "Saját"] + +const sortOptions = [ + { value: "date-asc", label: "📅↑" }, + { value: "date-desc", label: "📅↓" }, + { value: "abc-asc", label: "A→Z" }, + { value: "abc-desc", label: "Z→A" }, +] + +const ChooseDeck = () => { + const location = useLocation() + const locationUsername = location.state?.username ?? null + + // always call hook (hooks must be called unconditionally) and use as fallback + const [authUsername] = useRequireAuth({ key: "username", redirectTo: "/" }) + + // prefer passed username (from navigate state) over authenticated username + const username = locationUsername ?? authUsername + + const navigate = useNavigate() + + const [selectedType, setSelectedType] = useState("All") + const [selectedOrigin, setSelectedOrigin] = useState("Mind") + const [sortBy, setSortBy] = useState("date-desc") + const [search, setSearch] = useState("") + const [showSortHelp, setShowSortHelp] = useState(false) + const [allDecks, setAllDecks] = useState([]) + const [loading, setLoading] = useState(false) + const [selectedDeckIds, setSelectedDeckIds] = useState([]) + + // Load all decks once + useEffect(() => { + let mounted = true + const load = async () => { + setLoading(true) + try { + const result = await import("../../api/deckApi.js").then((m) => m.getDecksPage(0, 99)) + if (!mounted) return + + console.log("Loaded decks:", result) + + const mapped = (result.decks || []).map((d) => ({ + id: d.id, + name: d.name, + type: d.type === 2 ? "Question" : d.type === 1 ? "Joker" : "Luck", + created: d.creationdate ? new Date(d.creationdate).toLocaleDateString() : "", + origin: d.ctype === 2 ? "Vállalati" : d.ctype === 0 ? "Mind" : "Saját", + raw: d, + })) + + console.log("Mapped decks:", mapped) + setAllDecks(mapped) + } catch (err) { + console.error("Failed to load decks", err) + } finally { + setLoading(false) + } + } + load() + return () => { + mounted = false + } + }, []) + + // Filter logic + let filteredDecks = allDecks.filter((deck) => { + const typeMatch = selectedType === "All" || deck.type === selectedType + const originMatch = selectedOrigin === "Mind" || deck.origin === selectedOrigin + const searchMatch = !search || deck.name.toLowerCase().includes(search.toLowerCase()) + return typeMatch && originMatch && searchMatch + }) + + // Sort logic + filteredDecks = [...filteredDecks].sort((a, b) => { + if (sortBy === "date-asc") { + return a.created.localeCompare(b.created) + } else if (sortBy === "date-desc") { + return b.created.localeCompare(a.created) + } else if (sortBy === "abc-asc") { + return a.name.localeCompare(b.name) + } else if (sortBy === "abc-desc") { + return b.name.localeCompare(a.name) + } + return 0 + }) + + // Toggle deck selection + const toggleDeckSelection = (deckId) => { + setSelectedDeckIds((prev) => { + if (prev.includes(deckId)) { + return prev.filter((id) => id !== deckId) + } else { + return [...prev, deckId] + } + }) + } + + // Handle continue button + const handleContinue = () => { + if (selectedDeckIds.length === 0) { + alert("Kérlek válassz ki legalább egy paklit!") + return + } + console.log("Kiválasztott pakli ID-k:", selectedDeckIds) + navigate("/playersetup", { state: { deckIds: selectedDeckIds } }) + } + + return ( +
+
+ +
+ +
+ +
+ +
+ + {/* Title */} + + Válassz Paklikat a Játékhoz + + + + Válaszd ki azokat a paklikat, amelyekkel játszani szeretnél. Több paklit is kiválaszthatsz + egyszerre. + + + {/* Filters */} +
+
+ setSearch(e.target.value)} + width={240} + placeholder="Keresés..." + className="mr-4" + /> + + Típus: + + {deckTypes.map((type) => ( + + ))} + Eredet: + + + Rendezés: + + + +
+
+ + {showSortHelp && ( + setShowSortHelp(false)}> +

Rendezési lehetőségek

+
    +
  • + 📅↑ – Dátum szerint növekvő +
  • +
  • + 📅↓ – Dátum szerint csökkenő +
  • +
  • + A→Z – Név szerint növekvő +
  • +
  • + Z→A – Név szerint csökkenő +
  • +
+ +
+ )} + + {/* Selection Info */} +
+ + Kiválasztva: {selectedDeckIds.length} pakli + +
+ + {/* Decks Grid */} +
+ {loading && ( +
Betöltés...
+ )} + {!loading && filteredDecks.length === 0 && ( +
+ Nincsenek elérhető paklik. +
+ )} + {!loading && + filteredDecks.map((deck) => { + const deckType = deckTypes.find((t) => t.label === deck.type) + const borderColor = deckType ? deckType.color : "var(--color-success)" + const isSelected = selectedDeckIds.includes(deck.id) + + return ( +
toggleDeckSelection(deck.id)} + > + {/* Selection Indicator */} +
+ {isSelected ? ( + + ) : ( + + )} +
+ +
+ + {deck.type === "Luck" ? "Szerencse" : deck.type === "Question" ? "Kérdés" : "Joker"} + +

+ {deck.name} +

+
+
+ Létrehozva: {deck.created} +
+
+ ) + })} +
+ + {/* Continue Button */} +
+ +
+
+
+ +
+
+
+
+ ) +} + +export default ChooseDeck diff --git a/SerpentRace_Frontend/src/pages/Lobby/Lobby.jsx b/SerpentRace_Frontend/src/pages/Game/Lobby.jsx similarity index 96% rename from SerpentRace_Frontend/src/pages/Lobby/Lobby.jsx rename to SerpentRace_Frontend/src/pages/Game/Lobby.jsx index 00760124..a1d6368c 100644 --- a/SerpentRace_Frontend/src/pages/Lobby/Lobby.jsx +++ b/SerpentRace_Frontend/src/pages/Game/Lobby.jsx @@ -1,8 +1,8 @@ import React, { useEffect, useRef, useState } from "react" import { useNavigate, useLocation } from "react-router-dom" -import Navbar from "../../components/Navbar/Navbar" +import Navbar from "../../components/Navbar/Navbar.jsx" import Background from "../../assets/backgrounds/Background.jsx" -import useRequireAuth from "../../hooks/useRequireAuth" +import useRequireAuth from "../../hooks/useRequireAuth.jsx" const Lobby = () => { const [visible, setVisible] = useState(false) @@ -10,7 +10,6 @@ const Lobby = () => { const navigate = useNavigate() const location = useLocation() - const [user, setUser] = useRequireAuth() useEffect(() => { diff --git a/SerpentRace_Frontend/src/pages/Game/PlayerSetup.jsx b/SerpentRace_Frontend/src/pages/Game/PlayerSetup.jsx new file mode 100644 index 00000000..47d4b6d8 --- /dev/null +++ b/SerpentRace_Frontend/src/pages/Game/PlayerSetup.jsx @@ -0,0 +1,135 @@ +import React, { useState } from "react" +import { useNavigate, useLocation } from "react-router-dom" +import Navbar from "../../components/Navbar/Navbar.jsx" +import Background from "../../assets/backgrounds/Background.jsx" +import Footer from "../../components/Footer/Footer.jsx" +import useRequireAuth from "../../hooks/useRequireAuth.jsx" +import ButtonGreen from "../../components/Buttons/ButtonGreen.jsx" +import { motion } from "framer-motion" + +const PlayerSetup = () => { + const [username] = useRequireAuth({ key: "username", redirectTo: "/" }) + const navigate = useNavigate() + const location = useLocation() + + const deckIds = location.state?.deckIds || [] + + const [maxPlayers, setMaxPlayers] = useState(4) + const [isPublic, setIsPublic] = useState(true) + + const handleCreateLobby = () => { + const privacyFlag = isPublic ? 0 : 1 + console.log({ + deckIds, + playerCount: maxPlayers, + privacy: privacyFlag, + }) + // Itt küldd el az API-nak a lobby létrehozását + // navigate("/game-lobby", { state: { lobbyId: response.lobbyId } }) + } + + if (deckIds.length === 0) { + navigate("/choosedeck") + return null + } + + return ( +
+
+ +
+ +
+ +
+ +
+ + + Lobby Beállítások + + + + {deckIds.length} pakli kiválasztva. Add meg a játék részleteit. + + +
+ {/* Max Players */} +
+ + setMaxPlayers(parseInt(e.target.value) || 2)} + className="w-full px-4 py-2 rounded-lg bg-[color:var(--color-card)] text-[color:var(--color-text)] border border-[color:var(--color-surface)] focus:ring-2 focus:ring-[color:var(--color-success)] outline-none" + /> +
+ + {/* Public/Private */} +
+ +
+ + +
+
+
+ + {/* Action Buttons */} +
+ navigate("/choosedeck")} + width="w-auto px-8" + className="bg-gray-600 hover:bg-gray-700" + /> + +
+
+
+ +
+ ) +} + +export default PlayerSetup -- 2.52.0