deckcreate-oldal-javitas #62
@@ -20,7 +20,8 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance
|
|||||||
id: null,
|
id: null,
|
||||||
type: type,
|
type: type,
|
||||||
points: 10,
|
points: 10,
|
||||||
timeLimit: 30
|
timeLimit: 30,
|
||||||
|
consequence: { type: 0, value: 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -31,7 +32,8 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance
|
|||||||
question: '',
|
question: '',
|
||||||
options: ['', '', '', ''],
|
options: ['', '', '', ''],
|
||||||
correctAnswer: 0,
|
correctAnswer: 0,
|
||||||
explanation: ''
|
explanation: '',
|
||||||
|
wrongConsequence: { type: 1, value: 1 }
|
||||||
}
|
}
|
||||||
case 'JOKER':
|
case 'JOKER':
|
||||||
return {
|
return {
|
||||||
@@ -40,7 +42,8 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance
|
|||||||
description: '',
|
description: '',
|
||||||
effect: '',
|
effect: '',
|
||||||
actionType: 'skip',
|
actionType: 'skip',
|
||||||
usage: 'once'
|
usage: 'once',
|
||||||
|
wrongConsequence: { type: 1, value: 1 }
|
||||||
}
|
}
|
||||||
case 'LUCK':
|
case 'LUCK':
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -263,14 +263,6 @@ export default function CardsList({
|
|||||||
<div className="text-[color:var(--color-text)] font-semibold">
|
<div className="text-[color:var(--color-text)] font-semibold">
|
||||||
📊 Összesen: {cards.length} kártya
|
📊 Összesen: {cards.length} kártya
|
||||||
</div>
|
</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 === 'QUESTION').length}</span>
|
|
||||||
<span>🃏 {cards.filter(c => c.type === 'JOKER').length}</span>
|
|
||||||
<span>🎲 {cards.filter(c => c.type === 'LUCK').length}</span>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,17 +4,29 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { FaTheaterMasks, FaInfoCircle, FaUsers } from 'react-icons/fa'
|
import { FaTheaterMasks, FaInfoCircle, FaUsers } from 'react-icons/fa'
|
||||||
|
|
||||||
|
const consequenceTypes = [
|
||||||
|
{ value: 0, label: '⬆️ Előre lépés', description: 'A játékos előre lép X mezőt' },
|
||||||
|
{ value: 1, label: '⬇️ Hátra lépés', description: 'A játékos hátra lép X mezőt' },
|
||||||
|
{ value: 2, label: '⏸️ Kör kihagyás', description: 'A játékos kihagy egy kört' },
|
||||||
|
{ value: 3, label: '⏩ Extra kör', description: 'A játékos kap egy extra kört' },
|
||||||
|
{ value: 5, label: '🏁 Vissza a starthoz', description: 'A játékos visszakerül a starthoz' }
|
||||||
|
]
|
||||||
|
|
||||||
export default function JokerCardEditor({ card, onChange }) {
|
export default function JokerCardEditor({ card, onChange }) {
|
||||||
const [cardData, setCardData] = useState({
|
const [cardData, setCardData] = useState({
|
||||||
type: 'JOKER',
|
type: 'JOKER',
|
||||||
text: ''
|
text: '',
|
||||||
|
consequence: { type: 0, value: 1 },
|
||||||
|
wrongConsequence: { type: 1, value: 1 }
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (card) {
|
if (card) {
|
||||||
setCardData({
|
setCardData({
|
||||||
type: 'JOKER',
|
type: 'JOKER',
|
||||||
text: card.text || ''
|
text: card.text || '',
|
||||||
|
consequence: card.consequence || { type: 0, value: 1 },
|
||||||
|
wrongConsequence: card.wrongConsequence || { type: 1, value: 1 }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [card])
|
}, [card])
|
||||||
@@ -31,6 +43,36 @@ export default function JokerCardEditor({ card, onChange }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateConsequence = (field, value) => {
|
||||||
|
const newCardData = {
|
||||||
|
...cardData,
|
||||||
|
consequence: {
|
||||||
|
...cardData.consequence,
|
||||||
|
[field]: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setCardData(newCardData)
|
||||||
|
|
||||||
|
if (onChange) {
|
||||||
|
onChange(newCardData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateWrongConsequence = (field, value) => {
|
||||||
|
const newCardData = {
|
||||||
|
...cardData,
|
||||||
|
wrongConsequence: {
|
||||||
|
...cardData.wrongConsequence,
|
||||||
|
[field]: value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setCardData(newCardData)
|
||||||
|
|
||||||
|
if (onChange) {
|
||||||
|
onChange(newCardData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Példa joker kártyák
|
// Példa joker kártyák
|
||||||
const exampleCards = [
|
const exampleCards = [
|
||||||
"Felelsz vagy mersz? (Az előző játékos kérdez)",
|
"Felelsz vagy mersz? (Az előző játékos kérdez)",
|
||||||
@@ -57,18 +99,10 @@ export default function JokerCardEditor({ card, onChange }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-4xl mx-auto">
|
<div className="space-y-6">
|
||||||
|
{/* Info box */}
|
||||||
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
||||||
{/* Header */}
|
<div className="bg-[color:var(--color-fun)]/10 border border-[color:var(--color-fun)]/30 rounded-lg p-4">
|
||||||
<div className="flex items-center gap-3 mb-6">
|
|
||||||
<FaTheaterMasks className="text-2xl text-[color:var(--color-fun)]" />
|
|
||||||
<h3 className="text-xl font-bold text-[color:var(--color-text)]">
|
|
||||||
Joker Kártya Szerkesztő
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Info box */}
|
|
||||||
<div className="bg-[color:var(--color-fun)]/10 border border-[color:var(--color-fun)]/30 rounded-lg p-4 mb-6">
|
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<FaInfoCircle className="text-[color:var(--color-fun)] mt-1 flex-shrink-0" />
|
<FaInfoCircle className="text-[color:var(--color-fun)] mt-1 flex-shrink-0" />
|
||||||
<div>
|
<div>
|
||||||
@@ -86,28 +120,33 @@ export default function JokerCardEditor({ card, onChange }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Card text input */}
|
{/* Kártya szövege */}
|
||||||
<div className="space-y-4">
|
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
||||||
<div>
|
<h3 className="text-lg font-semibold text-[color:var(--color-text)] mb-4 flex items-center gap-2">
|
||||||
<label className="block text-[color:var(--color-text)] font-medium mb-2">
|
<FaTheaterMasks className="text-[color:var(--color-fun)]" />
|
||||||
Joker kártya feladat *
|
Kártya szövege
|
||||||
</label>
|
</h3>
|
||||||
<textarea
|
|
||||||
value={cardData.text}
|
<div>
|
||||||
onChange={handleTextChange}
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
placeholder="Pl: Felelsz vagy mersz? (Az előző játékos kérdez)"
|
Joker kártya feladat *
|
||||||
className="w-full h-32 p-4 bg-[color:var(--color-surface)] border border-[color:var(--color-border)] rounded-lg text-[color:var(--color-text)] placeholder-[color:var(--color-text-muted)] resize-none focus:outline-none focus:border-[color:var(--color-fun)] transition-colors"
|
</label>
|
||||||
maxLength={150}
|
<textarea
|
||||||
/>
|
value={cardData.text}
|
||||||
<div className="flex justify-between items-center mt-2">
|
onChange={handleTextChange}
|
||||||
<span className="text-xs text-[color:var(--color-text-muted)]">
|
placeholder="Pl: Felelsz vagy mersz? (Az előző játékos kérdez)"
|
||||||
Maximális hossz: 150 karakter
|
className="w-full h-32 px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] placeholder-[color:var(--color-text-muted)] resize-none focus:ring-2 focus:ring-[color:var(--color-fun)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
</span>
|
maxLength={150}
|
||||||
<span className="text-xs text-[color:var(--color-text-muted)]">
|
/>
|
||||||
{cardData.text.length}/150
|
<div className="flex justify-between items-center mt-2">
|
||||||
</span>
|
<span className="text-xs text-[color:var(--color-text-muted)]">
|
||||||
</div>
|
Maximális hossz: 150 karakter
|
||||||
|
</span>
|
||||||
|
<span className="text-xs text-[color:var(--color-text-muted)]">
|
||||||
|
{cardData.text.length}/150
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -147,6 +186,100 @@ export default function JokerCardEditor({ card, onChange }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Következmények (teljesítés esetén) */}
|
||||||
|
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
||||||
|
<h3 className="text-lg font-semibold text-[color:var(--color-text)] mb-4">
|
||||||
|
🎯 Következmények (teljesítés esetén)
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* Consequence Type */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Hatás típusa
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={cardData.consequence?.type ?? 0}
|
||||||
|
onChange={(e) => updateConsequence('type', parseInt(e.target.value))}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-success)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
>
|
||||||
|
{consequenceTypes.map(type => (
|
||||||
|
<option key={type.value} value={type.value}>
|
||||||
|
{type.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<div className="text-xs text-[color:var(--color-text-muted)] mt-1">
|
||||||
|
{consequenceTypes.find(t => t.value === (cardData.consequence?.type ?? 0))?.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Consequence Value - csak ha előre/hátra lépés */}
|
||||||
|
{(cardData.consequence?.type === 0 || cardData.consequence?.type === 1) && (
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Mezők száma
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={cardData.consequence?.value ?? 1}
|
||||||
|
onChange={(e) => updateConsequence('value', parseInt(e.target.value) || 1)}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-success)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
min="1"
|
||||||
|
max="10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Következmények (nem teljesítés esetén) */}
|
||||||
|
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
||||||
|
<h3 className="text-lg font-semibold text-[color:var(--color-text)] mb-4">
|
||||||
|
❌ Következmények (nem teljesítés esetén)
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* Wrong Consequence Type */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Hatás típusa
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={cardData.wrongConsequence?.type ?? 1}
|
||||||
|
onChange={(e) => updateWrongConsequence('type', parseInt(e.target.value))}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-danger)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
>
|
||||||
|
{consequenceTypes.map(type => (
|
||||||
|
<option key={type.value} value={type.value}>
|
||||||
|
{type.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<div className="text-xs text-[color:var(--color-text-muted)] mt-1">
|
||||||
|
{consequenceTypes.find(t => t.value === (cardData.wrongConsequence?.type ?? 1))?.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Wrong Consequence Value - csak ha előre/hátra lépés */}
|
||||||
|
{(cardData.wrongConsequence?.type === 0 || cardData.wrongConsequence?.type === 1) && (
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Mezők száma
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={cardData.wrongConsequence?.value ?? 1}
|
||||||
|
onChange={(e) => updateWrongConsequence('value', parseInt(e.target.value) || 1)}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-danger)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
min="1"
|
||||||
|
max="10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -4,17 +4,27 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import React, { useState, useEffect } from 'react'
|
||||||
import { FaDice, FaInfoCircle } from 'react-icons/fa'
|
import { FaDice, FaInfoCircle } from 'react-icons/fa'
|
||||||
|
|
||||||
|
const consequenceTypes = [
|
||||||
|
{ value: 0, label: '⬆️ Előre lépés', description: 'A játékos előre lép X mezőt' },
|
||||||
|
{ value: 1, label: '⬇️ Hátra lépés', description: 'A játékos hátra lép X mezőt' },
|
||||||
|
{ value: 2, label: '⏸️ Kör kihagyás', description: 'A játékos kihagy egy kört' },
|
||||||
|
{ value: 3, label: '⏩ Extra kör', description: 'A játékos kap egy extra kört' },
|
||||||
|
{ value: 5, label: '🏁 Vissza a starthoz', description: 'A játékos visszakerül a starthoz' }
|
||||||
|
]
|
||||||
|
|
||||||
export default function LuckCardEditor({ card, onChange }) {
|
export default function LuckCardEditor({ card, onChange }) {
|
||||||
const [cardData, setCardData] = useState({
|
const [cardData, setCardData] = useState({
|
||||||
type: 'LUCK',
|
type: 'LUCK',
|
||||||
text: ''
|
text: '',
|
||||||
|
consequence: { type: 0, value: 1 }
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (card) {
|
if (card) {
|
||||||
setCardData({
|
setCardData({
|
||||||
type: 'LUCK',
|
type: 'LUCK',
|
||||||
text: card.text || ''
|
text: card.text || '',
|
||||||
|
consequence: card.consequence || { type: 0, value: 1 }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [card])
|
}, [card])
|
||||||
@@ -31,19 +41,26 @@ export default function LuckCardEditor({ card, onChange }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const updateConsequence = (field, value) => {
|
||||||
<div className="max-w-4xl mx-auto">
|
const newCardData = {
|
||||||
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
...cardData,
|
||||||
{/* Header */}
|
consequence: {
|
||||||
<div className="flex items-center gap-3 mb-6">
|
...cardData.consequence,
|
||||||
<FaDice className="text-2xl text-[color:var(--color-luck)]" />
|
[field]: value
|
||||||
<h3 className="text-xl font-bold text-[color:var(--color-text)]">
|
}
|
||||||
Szerencse Kártya Szerkesztő
|
}
|
||||||
</h3>
|
setCardData(newCardData)
|
||||||
</div>
|
|
||||||
|
if (onChange) {
|
||||||
|
onChange(newCardData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{/* Info box */}
|
return (
|
||||||
<div className="bg-[color:var(--color-luck)]/10 border border-[color:var(--color-luck)]/30 rounded-lg p-4 mb-6">
|
<div className="space-y-6">
|
||||||
|
{/* Info box */}
|
||||||
|
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
||||||
|
<div className="bg-[color:var(--color-luck)]/10 border border-[color:var(--color-luck)]/30 rounded-lg p-4">
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-start gap-3">
|
||||||
<FaInfoCircle className="text-[color:var(--color-luck)] mt-1 flex-shrink-0" />
|
<FaInfoCircle className="text-[color:var(--color-luck)] mt-1 flex-shrink-0" />
|
||||||
<div>
|
<div>
|
||||||
@@ -60,28 +77,32 @@ export default function LuckCardEditor({ card, onChange }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Card text input */}
|
{/* Kártya szövege */}
|
||||||
<div className="space-y-4">
|
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
||||||
<div>
|
<h3 className="text-lg font-semibold text-[color:var(--color-text)] mb-4 flex items-center gap-2">
|
||||||
<label className="block text-[color:var(--color-text)] font-medium mb-2">
|
<FaDice className="text-[color:var(--color-luck)]" />
|
||||||
Kártya szövege *
|
Kártya szövege
|
||||||
</label>
|
</h3>
|
||||||
<textarea
|
<div>
|
||||||
value={cardData.text}
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
onChange={handleTextChange}
|
Szerencse esemény leírása *
|
||||||
placeholder="Pl: Órai projektekkel kiváltottál több vizsgát is! Lépj előre 4 mezőt"
|
</label>
|
||||||
className="w-full h-32 p-4 bg-[color:var(--color-surface)] border border-[color:var(--color-border)] rounded-lg text-[color:var(--color-text)] placeholder-[color:var(--color-text-muted)] resize-none focus:outline-none focus:border-[color:var(--color-luck)] transition-colors"
|
<textarea
|
||||||
maxLength={200}
|
value={cardData.text}
|
||||||
/>
|
onChange={handleTextChange}
|
||||||
<div className="flex justify-between items-center mt-2">
|
placeholder="Pl: Órai projektekkel kiváltottál több vizsgát is! Lépj előre 4 mezőt"
|
||||||
<span className="text-xs text-[color:var(--color-text-muted)]">
|
className="w-full h-32 px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] placeholder-[color:var(--color-text-muted)] resize-none focus:ring-2 focus:ring-[color:var(--color-luck)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
Maximális hossz: 200 karakter
|
maxLength={200}
|
||||||
</span>
|
/>
|
||||||
<span className="text-xs text-[color:var(--color-text-muted)]">
|
<div className="flex justify-between items-center mt-2">
|
||||||
{cardData.text.length}/200
|
<span className="text-xs text-[color:var(--color-text-muted)]">
|
||||||
</span>
|
Maximális hossz: 200 karakter
|
||||||
</div>
|
</span>
|
||||||
|
<span className="text-xs text-[color:var(--color-text-muted)]">
|
||||||
|
{cardData.text.length}/200
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -100,6 +121,53 @@ export default function LuckCardEditor({ card, onChange }) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Következmények */}
|
||||||
|
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
||||||
|
<h3 className="text-lg font-semibold text-[color:var(--color-text)] mb-4">
|
||||||
|
🎯 Következmények
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* Consequence Type */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Hatás típusa
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={cardData.consequence?.type ?? 0}
|
||||||
|
onChange={(e) => updateConsequence('type', parseInt(e.target.value))}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-luck)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
>
|
||||||
|
{consequenceTypes.map(type => (
|
||||||
|
<option key={type.value} value={type.value}>
|
||||||
|
{type.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<div className="text-xs text-[color:var(--color-text-muted)] mt-1">
|
||||||
|
{consequenceTypes.find(t => t.value === (cardData.consequence?.type ?? 0))?.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Consequence Value - csak ha előre/hátra lépés */}
|
||||||
|
{(cardData.consequence?.type === 0 || cardData.consequence?.type === 1) && (
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Mezők száma
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
max="10"
|
||||||
|
value={cardData.consequence?.value ?? 1}
|
||||||
|
onChange={(e) => updateConsequence('value', parseInt(e.target.value) || 1)}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-luck)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,14 @@ const timeLimits = [
|
|||||||
{ value: 120, label: '2 perc' }
|
{ value: 120, label: '2 perc' }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const consequenceTypes = [
|
||||||
|
{ value: 0, label: '⬆️ Előre lépés', description: 'A játékos előre lép X mezőt' },
|
||||||
|
{ value: 1, label: '⬇️ Hátra lépés', description: 'A játékos hátra lép X mezőt' },
|
||||||
|
{ value: 2, label: '⏸️ Kör kihagyás', description: 'A játékos kihagy egy kört' },
|
||||||
|
{ value: 3, label: '⏩ Extra kör', description: 'A játékos kap egy extra kört' },
|
||||||
|
{ value: 5, label: '🏁 Vissza a starthoz', description: 'A játékos visszakerül a starthoz' }
|
||||||
|
]
|
||||||
|
|
||||||
export default function TaskCardEditor({ card, onChange }) {
|
export default function TaskCardEditor({ card, onChange }) {
|
||||||
|
|
||||||
const updateField = (field, value) => {
|
const updateField = (field, value) => {
|
||||||
@@ -81,6 +89,26 @@ export default function TaskCardEditor({ card, onChange }) {
|
|||||||
onChange({ acceptedAnswers: newAnswers })
|
onChange({ acceptedAnswers: newAnswers })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateConsequence = (field, value) => {
|
||||||
|
const currentConsequence = card.consequence || { type: 0, value: 1 }
|
||||||
|
onChange({
|
||||||
|
consequence: {
|
||||||
|
...currentConsequence,
|
||||||
|
[field]: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateWrongConsequence = (field, value) => {
|
||||||
|
const currentWrongConsequence = card.wrongConsequence || { type: 1, value: 1 }
|
||||||
|
onChange({
|
||||||
|
wrongConsequence: {
|
||||||
|
...currentWrongConsequence,
|
||||||
|
[field]: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-4xl mx-auto space-y-6">
|
<div className="max-w-4xl mx-auto space-y-6">
|
||||||
{/* Feladat típus választó */}
|
{/* Feladat típus választó */}
|
||||||
@@ -513,6 +541,100 @@ export default function TaskCardEditor({ card, onChange }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Következmények (helyes válasz esetén) */}
|
||||||
|
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
||||||
|
<h3 className="text-lg font-semibold text-[color:var(--color-text)] mb-4">
|
||||||
|
🎯 Következmények (helyes válasz esetén)
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* Consequence Type */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Hatás típusa
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={card.consequence?.type ?? 0}
|
||||||
|
onChange={(e) => updateConsequence('type', parseInt(e.target.value))}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-success)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
>
|
||||||
|
{consequenceTypes.map(type => (
|
||||||
|
<option key={type.value} value={type.value}>
|
||||||
|
{type.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<div className="text-xs text-[color:var(--color-text-muted)] mt-1">
|
||||||
|
{consequenceTypes.find(t => t.value === (card.consequence?.type ?? 0))?.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Consequence Value - csak ha előre/hátra lépés */}
|
||||||
|
{(card.consequence?.type === 0 || card.consequence?.type === 1) && (
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Mezők száma
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={card.consequence?.value ?? 1}
|
||||||
|
onChange={(e) => updateConsequence('value', parseInt(e.target.value) || 1)}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-success)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
min="1"
|
||||||
|
max="10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Következmények (rossz válasz esetén) */}
|
||||||
|
<div className="bg-[color:var(--color-surface)] rounded-xl p-6">
|
||||||
|
<h3 className="text-lg font-semibold text-[color:var(--color-text)] mb-4">
|
||||||
|
❌ Következmények (rossz válasz esetén)
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* Wrong Consequence Type */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Hatás típusa
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={card.wrongConsequence?.type ?? 1}
|
||||||
|
onChange={(e) => updateWrongConsequence('type', parseInt(e.target.value))}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-danger)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
>
|
||||||
|
{consequenceTypes.map(type => (
|
||||||
|
<option key={type.value} value={type.value}>
|
||||||
|
{type.label}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
<div className="text-xs text-[color:var(--color-text-muted)] mt-1">
|
||||||
|
{consequenceTypes.find(t => t.value === (card.wrongConsequence?.type ?? 1))?.description}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Wrong Consequence Value - csak ha előre/hátra lépés */}
|
||||||
|
{(card.wrongConsequence?.type === 0 || card.wrongConsequence?.type === 1) && (
|
||||||
|
<div>
|
||||||
|
<label className="block text-[color:var(--color-text-muted)] text-sm font-medium mb-2">
|
||||||
|
Mezők száma
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={card.wrongConsequence?.value ?? 1}
|
||||||
|
onChange={(e) => updateWrongConsequence('value', parseInt(e.target.value) || 1)}
|
||||||
|
className="w-full px-4 py-2 rounded-xl bg-[color:var(--color-background)] border border-[color:var(--color-surface-selected)] text-[color:var(--color-text)] focus:ring-2 focus:ring-[color:var(--color-danger)] focus:border-transparent outline-none transition-all duration-200"
|
||||||
|
min="1"
|
||||||
|
max="10"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -51,9 +51,16 @@ export default function DeckCreator() {
|
|||||||
|
|
||||||
const handleSaveDeck = async () => {
|
const handleSaveDeck = async () => {
|
||||||
try {
|
try {
|
||||||
|
// Konvertálás: Frontend string -> Backend enum number
|
||||||
|
const typeMapping = {
|
||||||
|
'LUCK': 0,
|
||||||
|
'JOKER': 1,
|
||||||
|
'QUESTION': 2
|
||||||
|
}
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
name: deck.name,
|
name: deck.name,
|
||||||
type: deck.type,
|
type: typeMapping[deck.type] ?? 2, // Alapértelmezett: QUESTION
|
||||||
ctype: deck.privacy === 'public' ? 'PUBLIC' : 'PRIVATE',
|
ctype: deck.privacy === 'public' ? 'PUBLIC' : 'PRIVATE',
|
||||||
description: deck.description || '',
|
description: deck.description || '',
|
||||||
cards: deck.cards
|
cards: deck.cards
|
||||||
@@ -95,18 +102,30 @@ export default function DeckCreator() {
|
|||||||
|
|
||||||
const handleSaveCard = (cardData) => {
|
const handleSaveCard = (cardData) => {
|
||||||
try {
|
try {
|
||||||
|
// Biztosítjuk az alapértelmezett consequence értékeket
|
||||||
|
const defaultConsequence = { type: 0, value: 1 }
|
||||||
|
const defaultWrongConsequence = { type: 1, value: 1 }
|
||||||
|
|
||||||
const updatedCard = {
|
const updatedCard = {
|
||||||
...cardData,
|
...cardData,
|
||||||
id: isCreatingCard ? Date.now() : cardData.id
|
id: isCreatingCard ? Date.now() : cardData.id,
|
||||||
|
consequence: cardData.consequence || defaultConsequence,
|
||||||
|
// wrongConsequence csak QUESTION és JOKER típusoknál
|
||||||
|
...(cardData.type === 'QUESTION' || cardData.type === 'JOKER'
|
||||||
|
? { wrongConsequence: cardData.wrongConsequence || defaultWrongConsequence }
|
||||||
|
: {}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let wasInvalidCardDeleted = false
|
||||||
|
|
||||||
setDeck(prev => {
|
setDeck(prev => {
|
||||||
// Ellenőrizzük, vannak-e nem megfelelő típusú kártyák
|
// Ellenőrizzük, vannak-e nem megfelelő típusú kártyák
|
||||||
const invalidCards = prev.cards.filter(card => card.type !== prev.type)
|
const invalidCards = prev.cards.filter(card => card.type !== prev.type)
|
||||||
|
|
||||||
// Ha új kártyát mentünk megfelelő típussal és vannak nem megfelelők
|
// Ha új kártyát mentünk megfelelő típussal és vannak nem megfelelők
|
||||||
if (isCreatingCard && cardData.type === prev.type && invalidCards.length > 0) {
|
if (isCreatingCard && cardData.type === prev.type && invalidCards.length > 0) {
|
||||||
notifyWarning(`${invalidCards.length} db nem megfelelő típusú kártya törlésre került`)
|
wasInvalidCardDeleted = true
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
@@ -130,7 +149,13 @@ export default function DeckCreator() {
|
|||||||
setIsCreatingCard(false)
|
setIsCreatingCard(false)
|
||||||
setNewCardType(null)
|
setNewCardType(null)
|
||||||
|
|
||||||
notifySuccess('Kártya sikeresen mentve!')
|
// Csak egy értesítés
|
||||||
|
if (wasInvalidCardDeleted) {
|
||||||
|
const invalidCount = deck.cards.filter(card => card.type !== deck.type).length
|
||||||
|
notifyWarning(`Kártya mentve! ${invalidCount} db nem megfelelő típusú kártya törlésre került.`)
|
||||||
|
} else {
|
||||||
|
notifySuccess('Kártya sikeresen mentve!')
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Kártya mentési hiba:', error)
|
console.error('Kártya mentési hiba:', error)
|
||||||
notifyError('Hiba történt a kártya mentése során')
|
notifyError('Hiba történt a kártya mentése során')
|
||||||
|
|||||||
Reference in New Issue
Block a user