Files
SerpentRace/SerpentRace_Frontend/src/pages/Decks/Card_display.jsx
T

868 lines
44 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useEffect } from "react"
import { useParams } from "react-router-dom"
import HandleNavigate from "../../utils/HandleNavigate/HandleNavigate"
import {
FaArrowLeft,
FaFilter,
FaArrowUp,
FaArrowDown,
FaSortAlphaDown,
FaSortAlphaUp,
FaQuestionCircle,
FaChevronLeft,
FaChevronRight,
} from "react-icons/fa"
import Navbar from "../../components/Navbar/Navbar"
import SearchBox from "../../components/Search/SearchBox"
import PopUp from "../../components/PopUp/PopUp"
import { getDeckById } from "../../api/deckApi"
const Card_display = () => {
const { deckId } = useParams()
const { goDecks } = HandleNavigate()
const [deck, setDeck] = useState(null)
const [cards, setCards] = useState([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const [search, setSearch] = useState("")
const [sortBy, setSortBy] = useState("index")
const [showSortHelp, setShowSortHelp] = useState(false)
const [itemsPerPage, setItemsPerPage] = useState(20)
const [currentPage, setCurrentPage] = useState(1)
const [flippedCards, setFlippedCards] = useState(new Set()) // Track which cards are flipped
// Load deck and parse cards
useEffect(() => {
let mounted = true
const load = async () => {
setLoading(true)
setError(null)
try {
const result = await getDeckById(deckId)
if (!mounted) return
setDeck(result)
// Parse cards from JSON if it's a string
let parsedCards = []
if (result.cards) {
if (typeof result.cards === 'string') {
try {
parsedCards = JSON.parse(result.cards)
} catch (e) {
console.error('Failed to parse cards JSON:', e)
}
} else if (Array.isArray(result.cards)) {
parsedCards = result.cards
}
}
setCards(parsedCards)
} catch (err) {
console.error('Failed to load deck', err)
if (!mounted) return
setError(err.message || 'Hiba történt a pakli betöltése közben.')
} finally {
if (mounted) setLoading(false)
}
}
load()
return () => { mounted = false }
}, [deckId])
// Filter logic
let filteredCards = cards.filter((card) => {
if (!search) return true
const searchLower = search.toLowerCase()
// Check text field (or fallback to question/statement for old data)
const questionText = card.text || card.question || card.statement || ''
const questionMatch = questionText.toLowerCase().includes(searchLower)
const answersMatch = Array.isArray(card.options)
? card.options.some(opt => opt && opt.toLowerCase().includes(searchLower))
: Array.isArray(card.answers)
? card.answers.some(a => a && a.toLowerCase().includes(searchLower))
: false
return questionMatch || answersMatch
})
// Sort logic
filteredCards = [...filteredCards].sort((a, b) => {
if (sortBy === "index") {
// Keep original order
return 0
} else if (sortBy === "question-asc") {
const aText = a.text || a.question || a.statement || ''
const bText = b.text || b.question || b.statement || ''
return aText.localeCompare(bText)
} else if (sortBy === "question-desc") {
const aText = a.text || a.question || a.statement || ''
const bText = b.text || b.question || b.statement || ''
return bText.localeCompare(aText)
} else if (sortBy === "answers-asc") {
const aCount = Array.isArray(a.options) ? a.options.length : Array.isArray(a.answers) ? a.answers.length : 0
const bCount = Array.isArray(b.options) ? b.options.length : Array.isArray(b.answers) ? b.answers.length : 0
return aCount - bCount
} else if (sortBy === "answers-desc") {
const aCount = Array.isArray(a.options) ? a.options.length : Array.isArray(a.answers) ? a.answers.length : 0
const bCount = Array.isArray(b.options) ? b.options.length : Array.isArray(b.answers) ? b.answers.length : 0
return bCount - aCount
}
return 0
})
// Pagination logic
const totalCards = filteredCards.length
const totalPages = Math.ceil(totalCards / itemsPerPage)
const startIndex = (currentPage - 1) * itemsPerPage
const endIndex = startIndex + itemsPerPage
const paginatedCards = filteredCards.slice(startIndex, endIndex)
// Reset to page 1 when filters or items per page change
useEffect(() => {
setCurrentPage(1)
}, [search, sortBy, itemsPerPage])
const deckTypes = {
0: { label: "Szerencse", color: "var(--color-luck)" },
1: { label: "Joker", color: "var(--color-fun)" },
2: { label: "Kérdés", color: "var(--color-question)" },
}
// Card subtype Hungarian labels - UPDATED based on actual data
const cardSubTypeLabels = {
// String types (from DeckCreator)
"quiz": "Quiz ",
"truefalse": "Igaz/Hamis",
"text": "Szöveges válasz",
"matching": "Párosítás",
"QUESTION": "Kérdés",
"LUCK": "Szerencse",
"JOKER": "Joker",
"joker": "Joker",
"luck": "Szerencse",
// Backend CardType enum (numeric):
"0": "Quiz", // CardType.QUIZ = 0
"1": "Párosítás", // CardType.SENTENCE_PAIRING = 1
"2": "Szöveges válasz", // CardType.OWN_ANSWER = 2
"3": "Igaz/Hamis", // CardType.TRUE_FALSE = 3
"4": "Közelítés", // CardType.CLOSER = 4
0: "Quiz",
1: "Párosítás",
2: "Szöveges válasz",
3: "Igaz/Hamis",
4: "Közelítés"
}
const currentDeckType = deck ? (deckTypes[deck.type] || { label: "Ismeretlen", color: "var(--color-success)" }) : null
const toggleCardFlip = (cardId) => {
setFlippedCards(prev => {
const newSet = new Set(prev)
if (newSet.has(cardId)) {
newSet.delete(cardId)
} else {
newSet.add(cardId)
}
return newSet
})
}
return (
<div className="w-full min-h-screen bg-[color:var(--color-background)] flex flex-col">
<Navbar />
<main className="flex-1 w-full max-w-[1200px] mx-auto px-4 sm:px-6 py-6 sm:py-10">
{/* Header with back button */}
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-3 sm:gap-4 mb-6">
<button
onClick={() => goDecks()}
className="flex items-center gap-2 px-3 sm:px-4 py-2 rounded-lg sm:rounded-xl bg-[color:var(--color-surface)] text-[color:var(--color-text)] hover:bg-[color:var(--color-surface-selected)] transition-all duration-200 shadow text-sm"
>
<FaArrowLeft />
<span className="hidden sm:inline">Vissza a paklikhoz</span>
<span className="sm:hidden">Vissza</span>
</button>
{deck && (
<div className="flex flex-wrap items-center gap-2 sm:gap-3">
<h1 className="text-xl sm:text-2xl font-bold text-[color:var(--color-text)]">{deck.name}</h1>
{currentDeckType && (
<span
className="inline-block px-3 py-1 rounded-full text-sm font-bold"
style={{
background: currentDeckType.color,
color: "var(--color-text-inverse)",
}}
>
{currentDeckType.label}
</span>
)}
</div>
)}
</div>
{/* Loading / Error states */}
{loading && (
<div className="text-center text-[color:var(--color-text-muted)] py-10">
Betöltés...
</div>
)}
{error && (
<div className="text-center text-[color:var(--color-error)] py-10">
{error}
</div>
)}
{/* Filters and controls */}
{!loading && !error && (
<>
<div className="flex flex-col gap-3 mb-6 bg-[color:var(--color-surface)]/80 backdrop-blur-lg rounded-xl sm:rounded-2xl px-4 sm:px-6 py-3 sm:py-4 shadow-lg">
<div className="flex flex-col sm:flex-row gap-3 items-stretch sm:items-center w-full">
<SearchBox
value={search}
onChange={(e) => setSearch(e.target.value)}
width={300}
placeholder="Keresés..."
className="w-full sm:w-auto"
/>
<div className="flex items-center gap-2 flex-wrap">
<span className="text-[color:var(--color-text)] font-semibold text-sm sm:text-base flex items-center gap-1">
Rendezés:
<button
type="button"
className="ml-1 text-[color:var(--color-success)] hover:text-[color:var(--color-text)] focus:outline-none"
onClick={() => setShowSortHelp(true)}
aria-label="Rendezési magyarázat megnyitása"
style={{ fontSize: 18, lineHeight: 1 }}
>
<FaQuestionCircle />
</button>
</span>
<select
className="px-3 py-1 rounded-lg bg-[color:var(--color-success)]/10 hover:bg-[color:var(--color-success)]/30 text-[color:var(--color-text)] border-none focus:ring-2 focus:ring-[color:var(--color-success)] outline-none text-xs sm:text-sm flex-1 sm:flex-none"
style={{ backgroundColor: "rgba(0, 255, 0, 0.10)" }}
value={sortBy}
onChange={(e) => setSortBy(e.target.value)}
aria-label="Rendezés"
>
<option
value="index"
style={{ backgroundColor: "var(--color-surface)", color: "var(--color-text)" }}
>
Eredeti sorrend
</option>
<option
value="question-asc"
style={{ backgroundColor: "var(--color-surface)", color: "var(--color-text)" }}
>
Kérdés AZ
</option>
<option
value="question-desc"
style={{ backgroundColor: "var(--color-surface)", color: "var(--color-text)" }}
>
Kérdés ZA
</option>
<option
value="answers-asc"
style={{ backgroundColor: "var(--color-surface)", color: "var(--color-text)" }}
>
Válaszok száma
</option>
<option
value="answers-desc"
style={{ backgroundColor: "var(--color-surface)", color: "var(--color-text)" }}
>
Válaszok száma
</option>
</select>
</div>
</div>
</div>
{showSortHelp && (
<PopUp onClose={() => setShowSortHelp(false)}>
<h2 className="text-lg font-bold mb-4">Rendezési lehetőségek magyarázata</h2>
<ul className="space-y-2 text-[color:var(--color-night)]">
<li>
<span className="font-bold">Eredeti sorrend</span> A kártyák eredeti sorrendben jelennek meg
</li>
<li>
<span className="font-bold">Kérdés AZ</span> Kérdések ABC sorrendben (A-tól Z-ig)
</li>
<li>
<span className="font-bold">Kérdés ZA</span> Kérdések fordított ABC sorrendben (Z-től A-ig)
</li>
<li>
<span className="font-bold">Válaszok száma </span> Kevesebb választól a több válasz felé
</li>
<li>
<span className="font-bold">Válaszok száma </span> Több választól a kevesebb válasz felé
</li>
</ul>
<button
className="mt-6 px-4 py-2 rounded-lg bg-[color:var(--color-success)] text-[color:var(--color-text-inverse)] font-semibold hover:bg-[color:var(--color-success)]/80 transition"
onClick={() => setShowSortHelp(false)}
>
Bezárás
</button>
</PopUp>
)}
{/* Items per page selector and pagination info */}
<div className="flex flex-col sm:flex-row gap-3 sm:gap-4 justify-between items-center mb-6 bg-[color:var(--color-surface)]/60 backdrop-blur-lg rounded-xl px-4 sm:px-6 py-3 shadow">
<div className="flex items-center gap-2 sm:gap-3 w-full sm:w-auto justify-between sm:justify-start">
<span className="text-[color:var(--color-text-muted)] text-xs sm:text-sm font-medium">
Oldalanként:
</span>
<select
value={itemsPerPage}
onChange={(e) => setItemsPerPage(Number(e.target.value))}
className="px-2 sm:px-3 py-1.5 rounded-lg bg-[color:var(--color-background)] text-[color:var(--color-text)] border border-[color:var(--color-surface-selected)] focus:ring-2 focus:ring-[color:var(--color-success)] outline-none transition-all duration-200 text-sm"
>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={30}>30</option>
<option value={50}>50</option>
</select>
</div>
<div className="text-[color:var(--color-text-muted)] text-xs sm:text-sm text-center sm:text-left">
{totalCards > 0 ? (
<>
<span className="hidden sm:inline">{startIndex + 1}-{Math.min(endIndex, totalCards)} / {totalCards} kártya</span>
<span className="sm:hidden">{startIndex + 1}-{Math.min(endIndex, totalCards)} / {totalCards}</span>
</>
) : (
<>0 kártya</>
)}
</div>
</div>
{/* Cards Grid */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6 pb-20">
{totalCards === 0 && (
<div className="col-span-full text-center text-[color:var(--color-text-muted)] py-10">
Nincsenek kártyák ebben a pakliban.
</div>
)}
{paginatedCards.map((card, idx) => {
const cardIndex = startIndex + idx + 1
const questionText = card.text || card.question || card.statement || 'Kérdés hiányzik'
// Get answers based on card type
let answerOptions = []
let correctAnswerIndex = card.correctAnswer
// Detect card type - prioritize numeric card.type over subType
let detectedType = 'undefined'
// First check deck type - if deck is JOKER or LUCK type, cards inherit that
if (deck.type === 1) {
// Deck type 1 = Joker deck
detectedType = 'joker'
} else if (deck.type === 0) {
// Deck type 0 = Luck deck
detectedType = 'luck'
} else if (card.type !== undefined && card.type !== null) {
// Check by card.type field (numeric CardType enum)
const cardType = typeof card.type === 'string' ? card.type.toLowerCase() : card.type
if (cardType === 'joker' || card.type === 'JOKER') {
detectedType = 'joker'
} else if (cardType === 'luck' || card.type === 'LUCK') {
detectedType = 'luck'
} else if (card.type === 0) {
// type 0 = Quiz (multiple choice)
detectedType = 'quiz'
} else if (card.type === 1) {
// type 1 = Matching/Pairing
detectedType = 'matching'
} else if (card.type === 2) {
// type 2 = Text answer
detectedType = 'text'
} else if (card.type === 3) {
// type 3 = True/False
detectedType = 'truefalse'
}
} else if (card.subType) {
// Fallback to subType if card.type is missing
detectedType = String(card.subType).toLowerCase()
} else if (card.leftItems && card.rightItems && card.correctPairs) {
// Has leftItems, rightItems AND correctPairs = matching
detectedType = 'matching'
} else if (card.acceptedAnswers && card.acceptedAnswers.length > 0 && card.acceptedAnswers[0] && card.acceptedAnswers[0].trim()) {
// Only detect as text if acceptedAnswers has non-empty values
detectedType = 'text'
} else if (card.isTrue !== undefined) {
detectedType = 'truefalse'
} else if (card.options && Array.isArray(card.options) && card.options.some(opt => opt && opt.trim())) {
// Has non-empty options - must be multiple choice
detectedType = 'multiplechoice'
}
// Extract consequence info for JOKER and LUCK cards
let consequenceText = null
if ((detectedType === 'joker' || detectedType === 'luck') && card.consequence) {
const consequenceLabels = {
0: 'Lépj előre',
1: 'Lépj hátra',
2: 'Kör kihagyás',
3: 'Extra kör',
5: 'Vissza a starthoz'
}
const consequenceType = consequenceLabels[card.consequence.type] || 'Ismeretlen hatás'
const consequenceValue = card.consequence.value
if (consequenceValue && [0, 1].includes(card.consequence.type)) {
consequenceText = `${consequenceType} ${consequenceValue} mezőt`
} else if (consequenceValue && [2, 3].includes(card.consequence.type)) {
consequenceText = `${consequenceType} (${consequenceValue} kör)`
} else {
consequenceText = consequenceType
}
}
if (detectedType === 'truefalse' || detectedType === '3') {
// True/False cards
answerOptions = ['Igaz', 'Hamis']
// Parse answer from various sources
let isCorrectTrue = false
if (card.isTrue !== undefined) {
isCorrectTrue = card.isTrue
} else if (card.answer !== undefined) {
const answerStr = String(card.answer).toLowerCase()
isCorrectTrue = answerStr === 'true' || answerStr === '1' || answerStr === 'igaz'
} else if (card.correctAnswer !== undefined) {
isCorrectTrue = card.correctAnswer === 0 || card.correctAnswer === true || card.correctAnswer === 'true'
}
correctAnswerIndex = isCorrectTrue ? 0 : 1
} else if (detectedType === 'quiz' || detectedType === 'multiplechoice' || detectedType === '0') {
// Quiz/Multiple choice - parse from backend answer array or frontend options
if (card.answer && Array.isArray(card.answer) && card.answer.length > 0 && typeof card.answer[0] === 'object') {
// Backend format: [{answer: "A", text: "...", correct: boolean}]
answerOptions = card.answer.map(opt => opt.text || opt.label || '')
const correctOption = card.answer.find(opt => opt.correct)
correctAnswerIndex = card.answer.indexOf(correctOption)
} else if (card.options && Array.isArray(card.options)) {
// Frontend format: ["option1", "option2"]
answerOptions = card.options.filter(opt => opt && opt.trim())
correctAnswerIndex = card.correctAnswer
}
} else if (detectedType === 'matching' || detectedType === '1') {
// Matching cards - parse from backend answer array or frontend fields
if (card.answer && Array.isArray(card.answer) && card.answer.length > 0 && typeof card.answer[0] === 'object') {
// Backend format: [{left: "...", right: "..."}]
answerOptions = card.answer.map(pair => `${pair.left}${pair.right}`)
correctAnswerIndex = -1 // All pairs are correct
} else if (card.leftItems && card.rightItems && card.correctPairs) {
// Frontend format with leftItems, rightItems, correctPairs
const pairs = []
for (const [leftIdx, rightIdx] of Object.entries(card.correctPairs)) {
const left = card.leftItems[parseInt(leftIdx)]
const right = card.rightItems[parseInt(rightIdx)]
if (left && right) {
pairs.push(`${left}${right}`)
}
}
answerOptions = pairs
correctAnswerIndex = -1 // All pairs are correct
}
} else if (detectedType === 'text' || detectedType === '2') {
// OWN_ANSWER - parse from backend answer array or frontend acceptedAnswers
if (card.answer) {
// Backend format: ["answer1", "answer2"] or single value
answerOptions = Array.isArray(card.answer) ? card.answer : [card.answer]
correctAnswerIndex = -1 // All answers are correct
} else if (card.acceptedAnswers && Array.isArray(card.acceptedAnswers)) {
// Frontend format
answerOptions = card.acceptedAnswers
correctAnswerIndex = -1 // All accepted answers are correct
}
} else if (card.options && Array.isArray(card.options)) {
// Other types with options
answerOptions = card.options.filter(opt => opt && opt.trim())
} else if (card.answers && Array.isArray(card.answers)) {
// Other card types with answers array
answerOptions = card.answers.filter(opt => opt && opt.trim())
} else if (card.acceptedAnswers && Array.isArray(card.acceptedAnswers)) {
// Fallback for accepted answers
answerOptions = card.acceptedAnswers
correctAnswerIndex = -1
}
const answerCount = answerOptions.length
const cardId = card.id || idx
const isFlipped = flippedCards.has(cardId)
return (
<div
key={cardId}
className="relative h-80"
style={{ perspective: "1000px" }}
>
{detectedType === 'joker' ? (
// Joker card - no flip, just show the task
<div
className="w-full h-full bg-[color:var(--color-card)] rounded-2xl p-6 shadow-lg border-l-4 flex flex-col"
style={{
borderLeftColor: "var(--color-fun)",
}}
>
<div className="flex items-center justify-between mb-3">
<span className="text-[color:var(--color-text-muted)] text-sm font-medium">
Kártya #{cardIndex}
</span>
<span
className="inline-block px-2 py-1 rounded-full text-xs font-bold"
style={{
background: "var(--color-fun)",
color: "var(--color-text-inverse)",
}}
>
🃏 JOKER
</span>
</div>
<div className="flex-1 flex flex-col items-center justify-center">
<div className="text-6xl mb-4">🃏</div>
<div className="text-[color:var(--color-text)] text-center text-lg font-medium bg-[color:var(--color-fun)]/20 rounded-lg px-6 py-4 border-2 border-[color:var(--color-fun)]">
{questionText}
</div>
</div>
<div className="pt-3 border-t border-[color:var(--color-surface-selected)] text-xs text-[color:var(--color-text-muted)] text-center">
<div>Típus: <span className="font-semibold">Joker</span></div>
</div>
</div>
) : detectedType === 'luck' ? (
// Luck card - no flip, show text and consequence
<div
className="w-full h-full bg-[color:var(--color-card)] rounded-2xl p-6 shadow-lg border-l-4 flex flex-col"
style={{
borderLeftColor: "var(--color-luck)",
}}
>
<div className="flex items-center justify-between mb-3">
<span className="text-[color:var(--color-text-muted)] text-sm font-medium">
Kártya #{cardIndex}
</span>
<span
className="inline-block px-2 py-1 rounded-full text-xs font-bold"
style={{
background: "var(--color-luck)",
color: "var(--color-text-inverse)",
}}
>
🎲 SZERENCSE
</span>
</div>
<div className="flex-1 flex flex-col items-center justify-center">
<div className="text-6xl mb-4">🎲</div>
<div className="text-[color:var(--color-text)] text-center text-lg font-medium bg-[color:var(--color-luck)]/20 rounded-lg px-6 py-4 border-2 border-[color:var(--color-luck)] mb-4">
{questionText}
</div>
{consequenceText && (
<div className="text-[color:var(--color-text)] text-center">
<div className="text-xl font-bold bg-[color:var(--color-luck)]/30 rounded-lg px-6 py-3 border-2 border-[color:var(--color-luck)]">
{consequenceText}
</div>
</div>
)}
</div>
<div className="pt-3 border-t border-[color:var(--color-surface-selected)] text-xs text-[color:var(--color-text-muted)] text-center">
<div>Típus: <span className="font-semibold">Szerencse</span></div>
</div>
</div>
) : (
<div
className={`relative w-full h-full transition-transform duration-500 ${detectedType !== 'joker' && detectedType !== 'luck' ? 'cursor-pointer' : ''}`}
style={{
transformStyle: "preserve-3d",
transform: isFlipped ? "rotateY(180deg)" : "rotateY(0deg)"
}}
onClick={detectedType !== 'joker' && detectedType !== 'luck' ? () => toggleCardFlip(cardId) : undefined}
>
{/* Front side - Question */}
<div
className="absolute w-full h-full bg-[color:var(--color-card)] rounded-2xl p-6 shadow-lg border-l-4"
style={{
borderLeftColor: currentDeckType?.color || "var(--color-success)",
backfaceVisibility: "hidden"
}}
>
<div className="flex items-center justify-between mb-3">
<span className="text-[color:var(--color-text-muted)] text-sm font-medium">
Kártya #{cardIndex}
</span>
{detectedType !== 'joker' && detectedType !== 'luck' && (
<span
className="inline-block px-2 py-1 rounded-full text-xs font-bold"
style={{
background: currentDeckType?.color || "var(--color-success)",
color: "var(--color-text-inverse)",
}}
>
{answerCount} válasz
</span>
)}
{detectedType === 'joker' && (
<span
className="inline-block px-2 py-1 rounded-full text-xs font-bold"
style={{
background: "var(--color-fun)",
color: "var(--color-text-inverse)",
}}
>
🃏 JOKER
</span>
)}
{detectedType === 'luck' && (
<span
className="inline-block px-2 py-1 rounded-full text-xs font-bold"
style={{
background: "var(--color-luck)",
color: "var(--color-text-inverse)",
}}
>
🎲 SZERENCSE
</span>
)}
</div>
<h3 className="text-lg font-bold text-[color:var(--color-text)] mb-3">
{questionText}
</h3>
{/* Type info only */}
<div className="absolute bottom-6 left-6 right-6 pt-3 border-t border-[color:var(--color-surface-selected)] text-xs text-[color:var(--color-text-muted)]">
<div>Típus: <span className="font-semibold">
{cardSubTypeLabels[detectedType] || cardSubTypeLabels[card.subType] || cardSubTypeLabels[card.type] || detectedType || 'Ismeretlen'}
</span></div>
<div className="text-center mt-3 text-[color:var(--color-text-muted)] italic">
Kattints a megoldáshoz
</div>
</div>
</div>
{/* Back side - Answer */}
<div
className="absolute w-full h-full bg-[color:var(--color-card)] rounded-2xl p-6 shadow-lg border-l-4 overflow-y-auto"
style={{
borderLeftColor: currentDeckType?.color || "var(--color-success)",
backfaceVisibility: "hidden",
transform: "rotateY(180deg)"
}}
>
<div className="flex items-center justify-between mb-3">
<span className="text-[color:var(--color-text-muted)] text-sm font-medium">
{detectedType === 'joker' || detectedType === 'luck' ? 'Kártya hatás' : 'Megoldás'}
</span>
<span
className="inline-block px-2 py-1 rounded-full text-xs font-bold"
style={{
background: currentDeckType?.color || "var(--color-success)",
color: "var(--color-text-inverse)",
}}
>
{detectedType === 'joker' || detectedType === 'luck' ? (detectedType === 'joker' ? '🃏 JOKER' : '🎲 SZERENCSE') : `${answerCount} válasz`}
</span>
</div>
{detectedType === 'joker' ? (
// Joker card - just show the task/challenge
<div className="flex flex-col items-center justify-center h-full py-8">
<div className="text-6xl mb-4">🃏</div>
<div className="text-[color:var(--color-text)] text-center text-lg font-medium bg-[color:var(--color-fun)]/20 rounded-lg px-6 py-4 border-2 border-[color:var(--color-fun)]">
{questionText}
</div>
<div className="text-[color:var(--color-text-muted)] text-sm mt-4 text-center italic">
A játékmester dönti el a teljesítést
</div>
</div>
) : detectedType === 'luck' ? (
// Luck card - show consequence
<div className="flex flex-col items-center justify-center h-full py-8">
<div className="text-6xl mb-4">🎲</div>
{consequenceText && (
<div className="text-[color:var(--color-text)] text-center">
<div className="text-2xl font-bold mb-4 bg-[color:var(--color-luck)]/20 rounded-lg px-6 py-3 border-2 border-[color:var(--color-luck)]">
{consequenceText}
</div>
</div>
)}
<div className="text-[color:var(--color-text-muted)] text-sm mt-2 text-center italic">
Azonnal végrehajt
</div>
</div>
) : answerCount > 0 ? (
<div className="space-y-2">
<div className="text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
Helyes válasz:
</div>
{detectedType === 'truefalse' || detectedType === '3' ? (
// True/False - show only the correct answer
(() => {
// Determine if correct answer is true
let isCorrectTrue = false
if (card.isTrue !== undefined) {
isCorrectTrue = card.isTrue
} else if (card.answer !== undefined) {
const answerStr = String(card.answer).toLowerCase()
isCorrectTrue = answerStr === 'true' || answerStr === '1' || answerStr === 'igaz'
} else if (card.correctAnswer !== undefined) {
isCorrectTrue = card.correctAnswer === 0 || card.correctAnswer === true || card.correctAnswer === 'true'
}
return (
<div className="text-[color:var(--color-text)] text-lg font-bold bg-[color:var(--color-success)]/20 rounded-lg px-4 py-3 border-l-4 border-[color:var(--color-success)]">
{isCorrectTrue ? 'Igaz' : 'Hamis'}
</div>
)
})()
) : detectedType === 'matching' || detectedType === '1' ? (
// Matching - show all correct pairs
<ul className="space-y-2">
{answerOptions.map((pair, idx) => (
<li
key={idx}
className="text-[color:var(--color-text)] text-sm bg-[color:var(--color-success)]/20 rounded-lg px-3 py-2 border-l-2 border-[color:var(--color-success)] font-semibold"
>
{pair}
</li>
))}
</ul>
) : (detectedType === 'text' || detectedType === '2') && answerOptions.length > 0 ? (
// Text answers - show all accepted answers
<ul className="space-y-1">
{answerOptions.map((answer, ansIdx) => (
<li
key={ansIdx}
className="text-[color:var(--color-text)] text-sm bg-[color:var(--color-success)]/20 rounded-lg px-3 py-2 border-l-2 border-[color:var(--color-success)] font-semibold"
>
{answer}
</li>
))}
</ul>
) : (detectedType === 'quiz' || detectedType === 'multiplechoice' || detectedType === '0') && answerOptions.length > 0 ? (
// Quiz/Multiple choice - show all options with correct one highlighted
<ul className="space-y-2">
{answerOptions.map((option, ansIdx) => (
<li
key={ansIdx}
className={`text-[color:var(--color-text)] text-sm rounded-lg px-3 py-2 border-l-2 font-semibold ${
ansIdx === correctAnswerIndex
? 'bg-[color:var(--color-success)]/20 border-[color:var(--color-success)]'
: 'bg-[color:var(--color-surface)] border-[color:var(--color-surface-selected)]'
}`}
>
{ansIdx === correctAnswerIndex ? '✓ ' : ''}{String.fromCharCode(65 + ansIdx)}. {option}
</li>
))}
</ul>
) : (
// Other types - show only the correct answer
correctAnswerIndex !== undefined && correctAnswerIndex !== -1 && answerOptions[correctAnswerIndex] ? (
<div className="text-[color:var(--color-text)] text-lg font-bold bg-[color:var(--color-success)]/20 rounded-lg px-4 py-3 border-l-4 border-[color:var(--color-success)]">
{answerOptions[correctAnswerIndex]}
</div>
) : (
<div className="text-center text-[color:var(--color-text-muted)] py-4">
Nincs megadva helyes válasz
</div>
)
)}
</div>
) : (
<div className="text-center text-[color:var(--color-text-muted)] py-10">
Nincs elérhető válasz
</div>
)}
<div className="absolute bottom-6 left-6 right-6 text-center text-xs text-[color:var(--color-text-muted)] italic">
Kattints a kérdéshez
</div>
</div>
</div>
)}
</div>
)
})}
</div>
{/* Pagination Controls */}
{totalPages > 1 && (
<div className="flex flex-wrap justify-center items-center gap-2 mt-8">
<button
onClick={() => setCurrentPage(prev => Math.max(1, prev - 1))}
disabled={currentPage === 1}
className={`px-3 sm:px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-1 sm:gap-2 text-sm ${
currentPage === 1
? 'bg-[color:var(--color-surface)] text-[color:var(--color-text-muted)] cursor-not-allowed'
: 'bg-[color:var(--color-success)] text-[color:var(--color-text-inverse)] hover:bg-[color:var(--color-success)]/80 hover:scale-105'
}`}
>
<FaChevronLeft />
<span className="hidden sm:inline">Előző</span>
</button>
<div className="flex items-center gap-1 sm:gap-2">
{[...Array(totalPages)].map((_, index) => {
const pageNum = index + 1
if (
pageNum === 1 ||
pageNum === totalPages ||
(pageNum >= currentPage - 1 && pageNum <= currentPage + 1)
) {
return (
<button
key={pageNum}
onClick={() => setCurrentPage(pageNum)}
className={`w-8 h-8 sm:w-10 sm:h-10 rounded-lg font-medium transition-all duration-200 text-sm ${
currentPage === pageNum
? 'bg-[color:var(--color-success)] text-[color:var(--color-text-inverse)] scale-110 shadow-lg'
: 'bg-[color:var(--color-surface)] text-[color:var(--color-text)] hover:bg-[color:var(--color-surface-selected)]'
}`}
>
{pageNum}
</button>
)
} else if (
pageNum === currentPage - 2 ||
pageNum === currentPage + 2
) {
return (
<span key={pageNum} className="text-[color:var(--color-text-muted)]">
...
</span>
)
}
return null
})}
</div>
<button
onClick={() => setCurrentPage(prev => Math.min(totalPages, prev + 1))}
disabled={currentPage === totalPages}
className={`px-4 py-2 rounded-lg font-medium transition-all duration-200 flex items-center gap-2 ${
currentPage === totalPages
? 'bg-[color:var(--color-surface)] text-[color:var(--color-text-muted)] cursor-not-allowed'
: 'bg-[color:var(--color-success)] text-[color:var(--color-text-inverse)] hover:bg-[color:var(--color-success)]/80 hover:scale-105'
}`}
>
<span className="hidden sm:inline">Következő</span>
<FaChevronRight />
</button>
</div>
)}
</>
)}
</main>
</div>
)
}
export default Card_display