232 lines
7.3 KiB
React
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>
|
|
)
|
|
}
|