diff --git a/SerpentRace_Docker/docker-compose.watch.yml b/SerpentRace_Docker/docker-compose.watch.yml index b7e523ca..8d026a06 100644 --- a/SerpentRace_Docker/docker-compose.watch.yml +++ b/SerpentRace_Docker/docker-compose.watch.yml @@ -75,7 +75,9 @@ services: environment: - NODE_ENV=development - VITE_API_URL=http://localhost:3000 - volumes: [] + volumes: + - ../SerpentRace_Frontend:/app + - /app/node_modules develop: watch: - action: sync diff --git a/SerpentRace_Frontend/package-lock.json b/SerpentRace_Frontend/package-lock.json index e8e4cd88..02104eac 100644 --- a/SerpentRace_Frontend/package-lock.json +++ b/SerpentRace_Frontend/package-lock.json @@ -15,6 +15,7 @@ "react-dom": "^19.1.0", "react-icons": "^5.5.0", "react-router-dom": "^7.6.0", + "react-toastify": "^11.0.5", "tailwindcss": "^4.1.7" }, "devDependencies": { @@ -1816,6 +1817,15 @@ "node": ">=18" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3363,6 +3373,19 @@ "node": ">=18" } }, + "node_modules/react-toastify": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz", + "integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1" + }, + "peerDependencies": { + "react": "^18 || ^19", + "react-dom": "^18 || ^19" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", diff --git a/SerpentRace_Frontend/package.json b/SerpentRace_Frontend/package.json index 5bb119a6..d06aa2d6 100644 --- a/SerpentRace_Frontend/package.json +++ b/SerpentRace_Frontend/package.json @@ -17,6 +17,7 @@ "react-dom": "^19.1.0", "react-icons": "^5.5.0", "react-router-dom": "^7.6.0", + "react-toastify": "^11.0.5", "tailwindcss": "^4.1.7" }, "devDependencies": { diff --git a/SerpentRace_Frontend/src/components/DeckCreator/CardEditor.jsx b/SerpentRace_Frontend/src/components/DeckCreator/CardEditor.jsx index 8fb712f7..2fc5cbe3 100644 --- a/SerpentRace_Frontend/src/components/DeckCreator/CardEditor.jsx +++ b/SerpentRace_Frontend/src/components/DeckCreator/CardEditor.jsx @@ -20,29 +20,32 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance id: null, type: type, points: 10, - timeLimit: 30 + timeLimit: 30, + consequence: { type: 0, value: 1 } } switch (type) { - case 'task': + case 'QUESTION': return { ...baseData, subType: 'quiz', question: '', options: ['', '', '', ''], correctAnswer: 0, - explanation: '' + explanation: '', + wrongConsequence: { type: 1, value: 1 } } - case 'joker': + case 'JOKER': return { ...baseData, title: '', description: '', effect: '', actionType: 'skip', - usage: 'once' + usage: 'once', + wrongConsequence: { type: 1, value: 1 } } - case 'luck': + case 'LUCK': return { ...baseData, event: '', @@ -58,38 +61,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 === 'task') { - 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 +117,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,24 +147,47 @@ export default function CardEditor({ card, isCreating, cardType, onSave, onCance return (