Files
SerpentRace/SerpentRace_Frontend/src/components/DeckCreator/CardEditor.jsx
T
2025-10-22 09:30:09 +02:00

232 lines
7.3 KiB
React

// src/components/DeckCreator/CardEditor.jsx
// Jobb oldali kártya szerkesztő
import React, { useState, useEffect } from "react"
import { FaSave, FaTimes, FaEye } from "react-icons/fa"
import TaskCardEditor from "./TaskCardEditor.jsx"
import JokerCardEditor from "./JokerCardEditor.jsx"
import LuckCardEditor from "./LuckCardEditor.jsx"
import CardPreview from "./CardPreview.jsx"
import { notifySuccess, notifyError,notifyWarning } from "../../components/Toastify/toastifyServices"
export default function CardEditor({ card, isCreating, cardType, onSave, onCancel }) {
const [cardData, setCardData] = useState(null)
const [showPreview, setShowPreview] = useState(false)
// Alapértelmezett kártya adatok
const getDefaultCardData = (type) => {
const baseData = {
id: null,
type: type,
points: 10,
timeLimit: 30
}
switch (type) {
case 'task':
return {
...baseData,
subType: 'quiz',
question: '',
options: ['', '', '', ''],
correctAnswer: 0,
explanation: ''
}
case 'joker':
return {
...baseData,
title: '',
description: '',
effect: '',
actionType: 'skip',
usage: 'once'
}
case 'luck':
return {
...baseData,
event: '',
positiveEffect: '',
negativeEffect: '',
probability: 50,
risk: 'low'
}
default:
return baseData
}
}
// Kártya adatok inicializálása
useEffect(() => {
if (isCreating && cardType) {
setCardData(getDefaultCardData(cardType))
} else if (card) {
setCardData({ ...card })
} else {
setCardData(null)
}
}, [card, isCreating, cardType])
const validateCard = (data) => {
if (data.type === 'task') {
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.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
}
const updateCardData = (updates) => {
setCardData(prev => prev ? { ...prev, ...updates } : null)
}
const handleSave = () => {
if (!cardData) 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)))
}
}
// Ha nincs kiválasztott kártya vagy új kártya létrehozás
if (!cardData) {
return (
<div className="flex-1 flex items-center justify-center bg-[color:var(--color-background)]">
<div className="text-center">
<div className="text-6xl mb-4">🃏</div>
<div className="text-[color:var(--color-text)] text-xl font-semibold mb-2">
Válassz ki egy kártyát
</div>
<div className="text-[color:var(--color-text-muted)]">
Klikkelj egy kártyára a bal oldalon a szerkesztéshez,<br />
vagy hozz létre egy újat.
</div>
</div>
</div>
)
}
return (
<div className="flex-1 flex flex-col">
{/* 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">
<div className="flex items-center gap-3">
<div className="text-2xl">
{cardData.type === 'task' && '📋'}
{cardData.type === 'joker' && '🃏'}
{cardData.type === 'luck' && '🎲'}
</div>
<div>
<h2 className="text-xl font-bold text-[color:var(--color-text)]">
{isCreating ? 'Új' : 'Szerkesztés'}{' '}
{cardData.type === 'task' && 'Feladat kártya'}
{cardData.type === 'joker' && 'Joker kártya'}
{cardData.type === 'luck' && 'Szerencse kártya'}
</h2>
<div className="text-[color:var(--color-text-muted)] text-sm">
{cardData.type === 'task' && cardData.subType && (
<>
{cardData.subType === 'quiz' && 'Quiz (A/B/C/D)'}
{cardData.subType === 'truefalse' && 'Igaz/Hamis'}
{cardData.subType === 'matching' && 'Párosítás'}
{cardData.subType === 'text' && 'Szöveges válasz'}
</>
)}
</div>
</div>
</div>
<div className="flex items-center gap-3">
<button
onClick={() => setShowPreview(!showPreview)}
className={`
flex items-center gap-2 px-4 py-2 rounded-xl font-medium transition-all duration-200
${showPreview
? 'bg-[color:var(--color-success)] text-[color:var(--color-text-inverse)]'
: 'bg-[color:var(--color-background)] text-[color:var(--color-text)] hover:bg-[color:var(--color-surface-selected)]'
}
`}
>
<FaEye />
Előnézet
</button>
<button
onClick={() => {
notifyWarning('Kártya készítés megszakítva')
onCancel()
}}
className="flex items-center gap-2 px-4 py-2 rounded-xl bg-[color:var(--color-background)] hover:bg-[color:var(--color-surface-selected)] text-[color:var(--color-text)] transition-all duration-200"
>
<FaTimes />
Mégse
</button>
<button
onClick={handleSave}
className="flex items-center gap-2 px-6 py-2 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"
>
<FaSave />
Mentés
</button>
</div>
</div>
</div>
{/* Content */}
<div className="flex-1 overflow-hidden">
{showPreview ? (
<div className="h-full bg-[color:var(--color-background)] flex items-center justify-center p-6">
<CardPreview card={cardData} />
</div>
) : (
<div className="h-full overflow-y-auto p-6">
{cardData.type === 'task' && (
<TaskCardEditor
card={cardData}
onChange={updateCardData}
/>
)}
{cardData.type === 'joker' && (
<JokerCardEditor
card={cardData}
onChange={updateCardData}
/>
)}
{cardData.type === 'luck' && (
<LuckCardEditor
card={cardData}
onChange={updateCardData}
/>
)}
</div>
)}
</div>
</div>
)
}