Fix: Kártya típus kezelés javítása és joker kártyák megjelenítése

- Hozzáadva react-toastify a notifyWarning használatához
- Javítva a CardEditor fejléc hogy helyesen jelenítse meg az új kártya típusát
- Javítva a CardsList 'szerkesztés folyamatban' rész hogy QUESTION/JOKER/LUCK értékeket használjon
- Implementálva az automatikus nem megfelelő típusú kártyák törlése új kártya mentésekor
- Hozzáadva hibakezelés a kártya mentési logikához
- Joker típus címke változtatva 'Szórakozás'-ról 'Joker'-re
- Joker kártya szín változtatva citromsárgára (#FFD700)
- Docker watch mode volume konfiguráció javítása a hot reload-hoz
This commit is contained in:
GitG0r0
2025-10-22 23:21:19 +02:00
parent 0ca0e95540
commit edca8f84cd
10 changed files with 160 additions and 176 deletions
@@ -58,38 +58,55 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance
// Kártya adatok inicializálása
useEffect(() => {
if (isCreating && cardType) {
setCardData(getDefaultCardData(cardType))
} else if (card) {
setCardData({ ...card })
} else {
try {
if (isCreating && cardType) {
const defaultData = getDefaultCardData(cardType)
setCardData(defaultData)
} else if (card) {
setCardData({ ...card })
} else {
setCardData(null)
}
} catch (error) {
console.error('Kártya inicializálási hiba:', error)
setCardData(null)
}
}, [card, isCreating, cardType])
const validateCard = (data) => {
if (data.type === 'QUESTION') {
if (!data.question && !data.statement) {
notifyError("Kérdés vagy állítás megadása kötelező!")
try {
if (!data || !data.type) {
notifyError("Érvénytelen kártya adatok!")
return false
}
if (data.subType === 'quiz' && data.options.some(opt => !opt.trim())) {
notifyError("Minden válaszlehetőséget ki kell tölteni!")
return false
}
} else if (data.type === 'JOKER') {
if (!data.text || !data.text.trim()) {
notifyError("Joker kártya szövege nem lehet üres!")
return false
}
} else if (data.type === 'LUCK') {
if (!data.text || !data.text.trim()) {
notifyError("Szerencse kártya szövege nem lehet üres!")
return false
if (data.type === 'QUESTION') {
if (!data.question && !data.statement) {
notifyError("Kérdés vagy állítás megadása kötelező!")
return false
}
if (data.subType === 'quiz' && data.options && data.options.some(opt => !opt.trim())) {
notifyError("Minden válaszlehetőséget ki kell tölteni!")
return false
}
} else if (data.type === 'JOKER') {
if (!data.text || !data.text.trim()) {
notifyError("Joker kártya szövege nem lehet üres!")
return false
}
} else if (data.type === 'LUCK') {
if (!data.text || !data.text.trim()) {
notifyError("Szerencse kártya szövege nem lehet üres!")
return false
}
}
return true
} catch (error) {
console.error('Validálási hiba:', error)
notifyError("Hiba történt a kártya ellenőrzése során")
return false
}
return true
}
const updateCardData = (updates) => {
@@ -97,16 +114,14 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance
}
const handleSave = () => {
if (!cardData) return
if (!cardData) {
notifyError("Nincs mentendő kártya adat!")
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)))
}
onSave(cardData)
}
// Ha nincs kiválasztott kártya vagy új kártya létrehozás
@@ -129,6 +144,29 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance
return (
<div className="flex-1 flex flex-col">
{/* Type Mismatch Warning */}
{cardData?.type && cardType && cardData.type !== cardType && !isCreating && (
<div className="bg-[color:var(--color-error)]/10 border-l-4 border-[color:var(--color-error)] px-6 py-4">
<div className="flex items-center gap-3">
<div className="text-[color:var(--color-error)] text-xl"></div>
<div>
<div className="text-[color:var(--color-error)] font-semibold">
Figyelmeztetés: Nem megfelelő kártya típus
</div>
<div className="text-[color:var(--color-error)]/80 text-sm">
{`Ez egy ${
cardData.type === 'QUESTION' ? 'Feladat' :
cardData.type === 'JOKER' ? 'Joker' : 'Szerencse'
} kártya, de a pakli típusa ${
cardType === 'QUESTION' ? 'Feladat' :
cardType === 'JOKER' ? 'Joker' : 'Szerencse'
}.`}
</div>
</div>
</div>
</div>
)}
{/* Header */}
<div className="bg-[color:var(--color-surface)] border-b border-[color:var(--color-surface-selected)] px-6 py-4">
<div className="flex items-center justify-between">
@@ -140,17 +178,10 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance
</div>
<div>
<h2 className="text-xl font-bold text-[color:var(--color-text)]">
<<<<<<< HEAD
{isCreating ? 'Új' : 'Szerkesztés'} {' '}
{cardData.type === 'QUESTION' && 'Feladat kártya'}
{cardData.type === 'JOKER' && 'Joker kártya'}
{cardData.type === 'LUCK' && 'Szerencse kártya'}
=======
{isCreating ? 'Új' : 'Szerkesztés'} {' '}
{cardData.type === 'QUESTION' && 'Feladat kártya'}
{cardData.type === 'JOKER' && 'Joker kártya'}
{cardData.type === 'LUCK' && 'Szerencse kártya'}
>>>>>>> main
{(isCreating ? cardType : cardData.type) === 'QUESTION' && 'Feladat kártya'}
{(isCreating ? cardType : cardData.type) === 'JOKER' && 'Joker kártya'}
{(isCreating ? cardType : cardData.type) === 'LUCK' && 'Szerencse kártya'}
</h2>
<div className="text-[color:var(--color-text-muted)] text-sm">
{cardData.type === 'QUESTION' && cardData.subType && (
@@ -27,20 +27,12 @@ const cardSubTypeLabels = {
text: "Szöveges válasz"
}
<<<<<<< HEAD
export default function CardsList({
cards,
selectedCard,
deckType,
onSelectCard,
onCreateCard,
=======
export default function CardsList({
cards,
selectedCard,
onSelectCard,
onCreateCard,
>>>>>>> main
onDeleteCard,
isCreatingCard,
newCardType
@@ -48,7 +40,6 @@ export default function CardsList({
const [confirmingDelete, setConfirmingDelete] = useState(null)
const getCardPreview = (card) => {
<<<<<<< HEAD
if (card.type === 'QUESTION') {
return card.question || card.statement || 'Új feladat kártya'
}
@@ -57,44 +48,22 @@ export default function CardsList({
}
if (card.type === 'LUCK') {
return card.text || 'Új szerencse kártya'
=======
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'
>>>>>>> main
}
return "Ismeretlen kártya"
}
const getCardTypeLabel = (card) => {
<<<<<<< HEAD
if (card.type === 'QUESTION') {
=======
if (card.type === "task") {
>>>>>>> main
if (card.subType) {
return cardSubTypeLabels[card.subType] || "Feladat"
}
return "Feladat"
}
<<<<<<< HEAD
if (card.type === 'JOKER') {
return 'Joker'
}
if (card.type === 'LUCK') {
return 'Szerencse'
=======
if (card.type === "joker") {
return "Joker"
}
if (card.type === "luck") {
return "Szerencse"
>>>>>>> main
}
return "Ismeretlen"
}
@@ -119,11 +88,14 @@ export default function CardsList({
🃏 Kártyák
</h2>
<<<<<<< HEAD
{/* New Card Button */}
<button
onClick={() => onCreateCard(deckType)}
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"
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>
@@ -132,42 +104,6 @@ export default function CardsList({
{deckType === 'LUCK' && '🎲 Új szerencse kártya'}
</span>
</button>
=======
{/* 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>
>>>>>>> main
</div>
{/* Cards List */}
@@ -185,7 +121,7 @@ export default function CardsList({
)}
<div>
<div className="text-[color:var(--color-text)] font-medium">
Új {newCardType === "task" ? "feladat" : newCardType === "joker" ? "joker" : "szerencse"} kártya
Új {newCardType === "QUESTION" ? "feladat" : newCardType === "JOKER" ? "joker" : "szerencse"} kártya
</div>
<div className="text-[color:var(--color-text-muted)] text-sm">
Szerkesztés folyamatban...
@@ -205,14 +141,24 @@ export default function CardsList({
key={card.id}
onClick={() => onSelectCard(card)}
className={`
p-4 rounded-xl border cursor-pointer transition-all duration-200 hover:scale-105 group
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">
@@ -320,15 +266,9 @@ export default function CardsList({
{cards.length > 0 && (
<div className="flex justify-center gap-4 mt-2 text-xs text-[color:var(--color-text-muted)]">
<<<<<<< HEAD
<span>📋 {cards.filter(c => c.type === 'QUESTION').length}</span>
<span>🃏 {cards.filter(c => c.type === 'JOKER').length}</span>
<span>🎲 {cards.filter(c => c.type === 'LUCK').length}</span>
=======
<span>📋 {cards.filter(c => c.type === 'QUESTION').length}</span>
<span>🃏 {cards.filter(c => c.type === 'JOKER').length}</span>
<span>🎲 {cards.filter(c => c.type === 'LUCK').length}</span>
>>>>>>> main
</div>
)}
</div>
@@ -7,7 +7,7 @@ import { FaSave, FaArrowLeft, FaGlobe, FaLock, FaQuestionCircle, FaDice, FaLaugh
const deckTypes = [
{ value: "QUESTION", label: "Kérdés", icon: FaQuestionCircle, color: "var(--color-question)" },
{ value: "LUCK", label: "Szerencse", icon: FaDice, color: "var(--color-luck)" },
{ value: "JOKER", label: "Szórakozás", icon: FaLaughBeam, color: "var(--color-fun)" }
{ value: "JOKER", label: "Joker", icon: FaLaughBeam, color: "var(--color-fun)" }
]
const privacyOptions = [
@@ -17,7 +17,7 @@ import DeckInfoPopUp from "../PopUp/DeckInfoPopUp"
const deckTypes = [
{ label: "Luck", color: "var(--color-luck)" },
{ label: "Question", color: "var(--color-question)" },
{ label: "Fun", color: "var(--color-fun)" },
{ label: "Joker", color: "var(--color-fun)" },
]
// initial state will be fetched from backend
@@ -163,8 +163,8 @@ const DeckManager = () => {
? "Szerencse"
: type.label === "Question"
? "Kérdés"
: type.label === "Fun"
? "Szórakozás"
: type.label === "Joker"
? "Joker"
: type.label}
</button>
))}
@@ -303,7 +303,7 @@ const DeckManager = () => {
: deck.type === "Question"
? "Kérdés"
: deck.type === "Fun"
? "Szórakozás"
? "Joker"
: deck.type}
</span>
<h2 className="text-xl font-bold text-[color:var(--color-text)] mb-1 truncate">
@@ -32,7 +32,7 @@ export default function DeckInfoPopUp({ deck, onClose }) {
const deckTypes = {
"Luck": { label: "Szerencse", color: "var(--color-luck)" },
"Question": { label: "Kérdés", color: "var(--color-question)" },
"Fun": { label: "Szórakozás", color: "var(--color-fun)" }
"Fun": { label: "Joker", color: "var(--color-fun)" }
}
const currentDeckType = deckTypes[deck.type] || { label: deck.type, color: "var(--color-success)" }