// src/pages/DeckCreator/DeckCreator.jsx // Deck Creator Page - Deck létrehozás és szerkesztés import React, { useState, useEffect } from "react" import { useParams, useNavigate } from "react-router-dom" import Navbar from "../../components/Navbar/Navbar.jsx" import DeckHeader from "../../components/DeckCreator/DeckHeader.jsx" import CardsList from "../../components/DeckCreator/CardsList.jsx" import CardEditor from "../../components/DeckCreator/CardEditor.jsx" import { createDeck, getDeckById, updateDeck, deleteDeck } from '../../api/deckApi' import { notifySuccess, notifyError, notifyWarning } from "../../components/Toastify/toastifyServices" export default function DeckCreator() { const { deckId } = useParams() const navigate = useNavigate() // Deck alapadatok const [deck, setDeck] = useState({ id: null, name: "Új Pakli", type: "QUESTION", privacy: "private", description: "", cards: [] }) // UI állapotok const [selectedCard, setSelectedCard] = useState(null) const [isCreatingCard, setIsCreatingCard] = useState(false) const [newCardType, setNewCardType] = useState(null) const [isLoading, setIsLoading] = useState(false) const [showDeleteModal, setShowDeleteModal] = useState(false) // Betöltés API-ból useEffect(() => { if (deckId) { loadDeck(deckId) } else { setDeck({ id: null, name: "Új Pakli", type: "QUESTION", privacy: "private", description: "", cards: [] }) } }, [deckId]) const loadDeck = async (id) => { setIsLoading(true) try { const deckData = await getDeckById(id) console.log('Loaded deck:', deckData) // Type mapping from backend to frontend const typeMapping = { 0: 'LUCK', 1: 'JOKER', 2: 'QUESTION' } // CType mapping from backend to frontend const ctypeMapping = { 0: 'public', 1: 'private', 2: 'organization' } // Process cards: convert type field from number to string const processedCards = (deckData.cards || []).map(card => { // A kártya type mezője a deck type-ját tükrözi (backend így küldi) // Ezért a deck type alapján állítjuk be return { ...card, type: typeMapping[deckData.type] || 'QUESTION' } }) setDeck({ id: deckData.id, name: deckData.name || "Névtelen pakli", type: typeMapping[deckData.type] || 'QUESTION', privacy: ctypeMapping[deckData.ctype] || 'private', description: deckData.description || "", cards: processedCards, creationdate: deckData.creationdate, updatedate: deckData.updatedate }) // Success notification removed - silent load for better UX } catch (error) { console.error('Pakli betöltési hiba:', error) notifyError('Hiba történt a pakli betöltése során: ' + (error?.response?.data?.error || error.message)) navigate('/decks') } finally { setIsLoading(false) } } const handleDeckUpdate = (updates) => { setDeck(prev => ({ ...prev, ...updates })) } const handleSaveDeck = async () => { try { // Szűrjük ki a nem megfelelő típusú kártyákat const validCards = deck.cards.filter(card => card.type === deck.type) const invalidCardsCount = deck.cards.length - validCards.length // Ha voltak érvénytelen kártyák, frissítsük a state-et if (invalidCardsCount > 0) { setDeck(prev => ({ ...prev, cards: validCards })) // Értesítés a törölt kártyákról notifyWarning(`${invalidCardsCount} db nem megfelelő típusú kártya törölve a mentés előtt.`) } // Tisztítsuk meg a kártyákat - konvertáljuk a backend által várt formátumra const cleanedCards = validCards.map(card => { // Card subType mapping to backend CardType enum const cardTypeMapping = { 'quiz': 0, // QUIZ 'pairing': 1, // SENTENCE_PAIRING 'text': 2, // OWN_ANSWER 'truefalse': 3, // TRUE_FALSE 'closer': 4 // CLOSER } // Kezdjük az ID-val (ha van) const cleanedCard = {} if (card.id) { cleanedCard.id = card.id } // Ha van subType (QUESTION típusú kártyáknál), akkor add hozzá a type mezőt if (card.subType && cardTypeMapping[card.subType] !== undefined) { cleanedCard.type = cardTypeMapping[card.subType] } // Text mező - kötelező, különböző forrásokból jöhet cleanedCard.text = card.text || card.question || card.statement || "" // Egyéb frontend mezők, amiket a backend is elfogad if (card.question !== undefined) cleanedCard.question = card.question if (card.statement !== undefined) cleanedCard.statement = card.statement if (card.options !== undefined) cleanedCard.options = card.options if (card.correctAnswer !== undefined) cleanedCard.correctAnswer = card.correctAnswer if (card.leftItems !== undefined) cleanedCard.leftItems = card.leftItems if (card.rightItems !== undefined) cleanedCard.rightItems = card.rightItems if (card.correctPairs !== undefined) cleanedCard.correctPairs = card.correctPairs if (card.acceptedAnswers !== undefined) cleanedCard.acceptedAnswers = card.acceptedAnswers if (card.hint !== undefined) cleanedCard.hint = card.hint // Answer mező (ha van) if (card.answer !== undefined && card.answer !== null) { cleanedCard.answer = card.answer } // Csak LUCK típusú kártyáknál add hozzá a consequence-t if (deck.type === 'LUCK' && card.consequence) { cleanedCard.consequence = card.consequence } return cleanedCard }) // Típus konverzió backendhez const typeMapping = { 'LUCK': 0, 'JOKER': 1, 'QUESTION': 2 } const ctypeMapping = { 'public': 0, 'private': 1, 'organization': 2 } const payload = { name: deck.name?.trim() || "Névtelen pakli", type: typeMapping[deck.type] ?? 2, ctype: ctypeMapping[deck.privacy] ?? 1, cards: cleanedCards } // Note: description field is not sent to backend as it's not supported yet console.log('=== DECK SAVE DEBUG ===') console.log('Deck ID:', deck.id) console.log('Deck object:', deck) console.log('Payload to send:', payload) console.log('Is Update?', !!deck.id) let saved if (deck.id) { // Update existing deck console.log('Calling updateDeck with ID:', deck.id) saved = await updateDeck(deck.id, payload) console.log('Update response:', saved) notifySuccess('Pakli sikeresen frissítve!') } else { // Create new deck console.log('Calling createDeck') saved = await createDeck(payload) console.log('Create response:', saved) notifySuccess('Pakli sikeresen létrehozva!') } setDeck(prev => ({ ...prev, id: saved.id ?? prev.id, creationdate: saved.creationdate ?? prev.creationdate, updatedate: saved.updatedate ?? prev.updatedate })) console.log('Deck saved (backend):', saved) } catch (error) { console.error('=== DECK SAVE ERROR ===') console.error('Full error:', error) console.error('Error response:', error?.response) console.error('Error response data:', error?.response?.data) console.error('Error message:', error?.message) const errorMessage = error?.response?.data?.error || error?.response?.data?.message || error?.message || 'Ismeretlen hiba történt' notifyError('Hiba történt a mentés során: ' + errorMessage) } } const handleBack = () => { navigate("/decks") } const handleDeleteDeck = () => { if (!deck.id) { notifyWarning('Nincs mit törölni - a pakli még nincs elmentve!') return } setShowDeleteModal(true) } const handleConfirmDelete = async () => { try { await deleteDeck(deck.id) setShowDeleteModal(false) notifySuccess('Pakli sikeresen törölve!') navigate('/decks') } catch (error) { console.error('Pakli törlési hiba:', error) const errorMessage = error?.response?.data?.error || error?.response?.data?.message || error?.message || 'Ismeretlen hiba történt' notifyError('Hiba történt a törlés során: ' + errorMessage) setShowDeleteModal(false) } } const handleCancelDelete = () => { setShowDeleteModal(false) } const handleCreateCard = (cardType) => { setNewCardType(cardType) setIsCreatingCard(true) setSelectedCard(null) } const handleSelectCard = (card) => { setSelectedCard(card) setIsCreatingCard(false) setNewCardType(null) } // 💡 Demo verzió: beállítások szekció kihagyva const handleSaveCard = (cardData) => { try { if (cardData.section === "settings") { console.log("Beállítások szekció kihagyva (demo verzió)") return } // Alapértelmezett consequence csak LUCK típusú kártyákhoz const updatedCard = { ...cardData, id: isCreatingCard ? Date.now() : cardData.id } // Csak LUCK típusú kártyákhoz add hozzá a consequence-t if (cardData.type === 'LUCK') { updatedCard.consequence = cardData.consequence || { type: 0, value: 1 } } let wasInvalidCardDeleted = false setDeck(prev => { const invalidCards = prev.cards.filter(card => card.type !== prev.type) if (isCreatingCard && cardData.type === prev.type && invalidCards.length > 0) { wasInvalidCardDeleted = true return { ...prev, cards: [ ...prev.cards.filter(card => card.type === prev.type), updatedCard ] } } return { ...prev, cards: isCreatingCard ? [...prev.cards, updatedCard] : prev.cards.map(card => card.id === updatedCard.id ? updatedCard : card) } }) setSelectedCard(updatedCard) setIsCreatingCard(false) setNewCardType(null) 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) { console.error('Kártya mentési hiba:', error) notifyError('Hiba történt a kártya mentése során') } } // 💬 Felugró ablak törlés előtt const handleDeleteCard = (cardId) => { const confirmDelete = window.confirm("Biztosan törölni szeretnéd ezt a kártyát?") if (!confirmDelete) return setDeck(prev => ({ ...prev, cards: prev.cards.filter(card => card.id !== cardId) })) if (selectedCard?.id === cardId) { setSelectedCard(null) } notifySuccess("Kártya törölve a pakliból!") } return (
{isLoading ? (
Pakli betöltése...
Kérlek várj, amíg betöltjük a pakli adatait.
) : (
{/* Deck Header */} {/* Main Content */}
{/* Left Panel - Cards List */}
{/* Right Panel - Card Editor */}
{ setIsCreatingCard(false) setNewCardType(null) setSelectedCard(null) }} />
)} {/* Delete Confirmation Modal */} {showDeleteModal && (
🗑️

Biztosan törölni szeretnéd a(z) "{deck.name}" paklit?

Ez a művelet nem visszavonható!

)}
) }