Files
SerpentRace/SerpentRace_Frontend/src/components/DeckCreator/CardsList.jsx
T
2025-10-22 14:24:24 +02:00

286 lines
11 KiB
React
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// src/components/DeckCreator/CardsList.jsx
// Bal oldali kártyák listája és új kártya létrehozás
import React, { useState } from "react"
import {
FaPlus,
FaEdit,
FaTrash,
FaQuestionCircle,
FaCheck,
FaTimes,
FaDice,
FaTheaterMasks
} from "react-icons/fa"
import { notifySuccess, notifyError } from "../../components/Toastify/toastifyServices"
const cardTypeIcons = {
task: { icon: FaQuestionCircle, color: "var(--color-question)" },
joker: { icon: FaTheaterMasks, color: "var(--color-fun)" },
luck: { icon: FaDice, color: "var(--color-luck)" }
}
const cardSubTypeLabels = {
quiz: "Quiz",
truefalse: "Igaz/Hamis",
matching: "Párosítás",
text: "Szöveges válasz"
}
export default function CardsList({
cards,
selectedCard,
onSelectCard,
onCreateCard,
onDeleteCard,
isCreatingCard,
newCardType
}) {
const [confirmingDelete, setConfirmingDelete] = useState(null)
const getCardPreview = (card) => {
if (card.type === "task") {
return card.question || card.statement || "Új feladat kártya"
}
if (card.type === "joker") {
return card.text || "Új joker kártya"
}
if (card.type === "luck") {
return card.text || "Új szerencse kártya"
}
return "Ismeretlen kártya"
}
const getCardTypeLabel = (card) => {
if (card.type === "task") {
if (card.subType) {
return cardSubTypeLabels[card.subType] || "Feladat"
}
return "Feladat"
}
if (card.type === "joker") {
return "Joker"
}
if (card.type === "luck") {
return "Szerencse"
}
return "Ismeretlen"
}
const handleConfirmDelete = () => {
if (confirmingDelete) {
onDeleteCard(confirmingDelete)
notifySuccess("Kártya sikeresen törölve a pakliból!")
setConfirmingDelete(null)
}
}
const handleCancelDelete = () => {
setConfirmingDelete(null)
}
return (
<div className="flex flex-col h-full relative">
{/* Header */}
<div className="p-4 border-b border-[color:var(--color-surface-selected)]">
<h2 className="text-lg font-bold text-[color:var(--color-text)] mb-4 flex items-center gap-2">
🃏 Kártyák
</h2>
{/* New Card Dropdown */}
<div className="relative group">
<button className="w-full flex items-center justify-center gap-2 px-4 py-3 rounded-xl bg-[color:var(--color-success)] hover:bg-[color:var(--color-success)]/80 text-[color:var(--color-text-inverse)] font-semibold transition-all duration-200 hover:scale-105 shadow-lg">
<FaPlus />
Új kártya
</button>
{/* Dropdown Menu */}
<div className="absolute top-full left-0 right-0 mt-2 bg-[color:var(--color-card)] rounded-xl shadow-lg border border-[color:var(--color-surface-selected)] opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-10">
<button
onClick={() => onCreateCard("task")}
className="w-full flex items-center gap-3 px-4 py-3 hover:bg-[color:var(--color-surface-selected)] text-[color:var(--color-text)] transition-colors duration-200 rounded-t-xl"
>
<FaQuestionCircle className="text-[color:var(--color-question)]" />
📋 Feladat kártya
</button>
<button
onClick={() => onCreateCard("joker")}
className="w-full flex items-center gap-3 px-4 py-3 hover:bg-[color:var(--color-surface-selected)] text-[color:var(--color-text)] transition-colors duration-200"
>
<FaTheaterMasks className="text-[color:var(--color-fun)]" />
🃏 Joker kártya
</button>
<button
onClick={() => onCreateCard("luck")}
className="w-full flex items-center gap-3 px-4 py-3 hover:bg-[color:var(--color-surface-selected)] text-[color:var(--color-text)] transition-colors duration-200 rounded-b-xl"
>
<FaDice className="text-[color:var(--color-luck)]" />
🎲 Szerencse kártya
</button>
</div>
</div>
</div>
{/* Cards List */}
<div className="flex-1 overflow-y-auto p-4 space-y-3">
{/* Creating Card Indicator */}
{isCreatingCard && (
<div className="bg-[color:var(--color-background)]/50 border-2 border-dashed border-[color:var(--color-success)] rounded-xl p-4 animate-pulse">
<div className="flex items-center gap-3">
{newCardType && (
<div className="flex items-center justify-center w-8 h-8 rounded-full bg-[color:var(--color-success)]/20">
{React.createElement(cardTypeIcons[newCardType]?.icon || FaQuestionCircle, {
className: "text-[color:var(--color-success)] text-sm"
})}
</div>
)}
<div>
<div className="text-[color:var(--color-text)] font-medium">
Új {newCardType === "task" ? "feladat" : newCardType === "joker" ? "joker" : "szerencse"} kártya
</div>
<div className="text-[color:var(--color-text-muted)] text-sm">
Szerkesztés folyamatban...
</div>
</div>
</div>
</div>
)}
{/* Existing Cards */}
{cards.map((card, index) => {
const cardIcon = cardTypeIcons[card.type] || cardTypeIcons.task
const isSelected = selectedCard?.id === card.id
return (
<div
key={card.id}
onClick={() => onSelectCard(card)}
className={`
p-4 rounded-xl border cursor-pointer transition-all duration-200 hover:scale-105 group
${
isSelected
? "bg-[color:var(--color-success)]/10 border-[color:var(--color-success)] shadow-lg"
: "bg-[color:var(--color-background)]/50 border-[color:var(--color-surface-selected)] hover:bg-[color:var(--color-background)]/80"
}
`}
>
{/* Card Header */}
<div className="flex items-start justify-between gap-2 mb-3">
<div className="flex items-center gap-3 flex-1 min-w-0">
<div
className="flex items-center justify-center w-10 h-10 rounded-full border-2"
style={{ borderColor: cardIcon.color }}
>
{React.createElement(cardIcon.icon, {
style: { color: cardIcon.color },
className: "text-lg"
})}
</div>
<div className="flex-1 min-w-0">
<div className="text-[color:var(--color-text)] font-bold text-sm mb-1">
#{index + 1} - {getCardTypeLabel(card)}
</div>
{card.timeLimit && (
<div className="text-[color:var(--color-text-muted)] text-xs flex items-center gap-1">
{card.timeLimit} másodperc
</div>
)}
</div>
</div>
{/* Action Buttons */}
<div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
<button
onClick={(e) => {
e.stopPropagation()
setConfirmingDelete(card.id)
}}
className="p-1.5 rounded-lg bg-[color:var(--color-error)]/10 hover:bg-[color:var(--color-error)]/20 text-[color:var(--color-error)] transition-colors duration-200"
>
<FaTrash className="text-xs" />
</button>
</div>
</div>
{/* Card Content Preview */}
<div className="bg-[color:var(--color-surface)]/30 rounded-lg p-3 mb-2">
<div
className="text-[color:var(--color-text)] text-sm leading-relaxed"
style={{
display: "-webkit-box",
WebkitLineClamp: 2,
WebkitBoxOrient: "vertical",
overflow: "hidden"
}}
>
{getCardPreview(card)}
</div>
</div>
</div>
)
})}
{/* Empty State */}
{cards.length === 0 && !isCreatingCard && (
<div className="text-center py-12">
<div className="text-[color:var(--color-text-muted)] text-lg mb-2">🃏</div>
<div className="text-[color:var(--color-text-muted)] text-sm">
Még nincsenek kártyák.
<br />
Hozz létre az első kártyát!
</div>
</div>
)}
</div>
{/* Confirm Delete Popup */}
{confirmingDelete && (
<div className="fixed inset-0 bg-black/40 flex items-center justify-center z-50">
<div className="bg-white rounded-xl shadow-xl p-6 w-80 text-center animate-fadeIn">
<h3 className="text-lg font-semibold mb-4 text-gray-800">
Biztosan törölni szeretnéd?
</h3>
<p className="text-sm text-gray-600 mb-6">
Ez a művelet nem visszavonható.
</p>
<div className="flex justify-center gap-4">
<button
onClick={handleConfirmDelete}
className="bg-[color:var(--color-error)] text-white px-4 py-2 rounded-lg hover:bg-red-600 transition"
>
Igen
</button>
<button
onClick={handleCancelDelete}
className="bg-gray-200 px-4 py-2 rounded-lg hover:bg-gray-300 transition"
>
Mégse
</button>
</div>
</div>
</div>
)}
{/* Footer Stats */}
<div className="p-4 border-t border-[color:var(--color-surface-selected)] bg-[color:var(--color-background)]/30">
<div className="text-center">
<div className="text-[color:var(--color-text)] font-semibold">
📊 Összesen: {cards.length} kártya
</div>
{cards.length > 0 && (
<div className="flex justify-center gap-4 mt-2 text-xs text-[color:var(--color-text-muted)]">
<span>📋 {cards.filter((c) => c.type === "task").length}</span>
<span>🃏 {cards.filter((c) => c.type === "joker").length}</span>
<span>🎲 {cards.filter((c) => c.type === "luck").length}</span>
</div>
)}
</div>
</div>
</div>
)
}