3bbd3f1e8a
- TaskCardEditor: Consequence és wrongConsequence kezelés hozzáadva - JokerCardEditor: Teljesítés és nem teljesítés consequence-ek - LuckCardEditor: Szerencse kártyák consequence kezelése - CardEditor: Alapértelmezett consequence értékek az új kártyákhoz - DeckCreator: Consequence mezők biztosítása mentéskor - CardsList: Következmény típusok megjelenítése - UI javítás: Mind a három editor külön szekciókba rendezve (info, szöveg, következmények) - Egységes struktúra és design az összes kártya szerkesztőnél
271 lines
9.9 KiB
React
271 lines
9.9 KiB
React
// 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 = {
|
||
QUESTION: { 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,
|
||
deckType,
|
||
onSelectCard,
|
||
onCreateCard,
|
||
onDeleteCard,
|
||
isCreatingCard,
|
||
newCardType
|
||
}) {
|
||
const [confirmingDelete, setConfirmingDelete] = useState(null)
|
||
|
||
const getCardPreview = (card) => {
|
||
if (card.type === 'QUESTION') {
|
||
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 === 'QUESTION') {
|
||
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 Button */}
|
||
<button
|
||
onClick={() => onCreateCard(deckType)}
|
||
className={`w-full flex items-center justify-center gap-2 px-4 py-3 rounded-xl text-[color:var(--color-text-inverse)] font-semibold transition-all duration-200 hover:scale-105 shadow-lg ${
|
||
deckType === 'QUESTION' ? 'bg-[color:var(--color-question)] hover:bg-[color:var(--color-question)]/80' :
|
||
deckType === 'LUCK' ? 'bg-[color:var(--color-luck)] hover:bg-[color:var(--color-luck)]/80' :
|
||
'bg-[color:var(--color-fun)] hover:bg-[color:var(--color-fun)]/80'
|
||
}`}
|
||
>
|
||
<FaPlus />
|
||
<span>
|
||
{deckType === 'QUESTION' && '📋 Új feladat kártya'}
|
||
{deckType === 'JOKER' && '🃏 Új joker kártya'}
|
||
{deckType === 'LUCK' && '🎲 Új szerencse kártya'}
|
||
</span>
|
||
</button>
|
||
</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 === "QUESTION" ? "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 relative
|
||
${
|
||
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.type !== deckType ? "opacity-70" : ""}
|
||
`}
|
||
>
|
||
{card.type !== deckType && (
|
||
<div className="absolute inset-0 flex items-center justify-center">
|
||
<div className="absolute inset-0 bg-[color:var(--color-error)]/5 backdrop-blur-[1px] rounded-xl"></div>
|
||
<div className="absolute rotate-[-15deg] border-t-2 border-[color:var(--color-error)] w-full"></div>
|
||
<span className="absolute top-1 right-1 text-xs text-[color:var(--color-error)] bg-[color:var(--color-error)]/10 px-2 py-1 rounded-lg">
|
||
⚠️ Nem megfelelő típus
|
||
</span>
|
||
</div>
|
||
)}
|
||
{/* 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>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|