diff --git a/public/app.js b/public/app.js index 74092d6..f288391 100644 --- a/public/app.js +++ b/public/app.js @@ -4749,15 +4749,32 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.` const saveComicsProjectFlow = async (forceNew = false) => { let titulo = comicsProjectTitleInput ? comicsProjectTitleInput.value.trim() : ''; + let tema = comicsTemaInput ? comicsTemaInput.value.trim() : ''; + if (!titulo) { - titulo = comicsResultTitle ? comicsResultTitle.textContent.trim() : 'Minha História em Quadrinhos'; + if (comicsResultTitle && comicsResultTitle.textContent.trim() && comicsResultTitle.textContent.trim() !== 'Resultado da História em Quadrinhos') { + titulo = comicsResultTitle.textContent.trim(); + } else if (tema) { + titulo = tema; + } else { + titulo = 'Minha História em Quadrinhos'; + } + if (comicsProjectTitleInput) comicsProjectTitleInput.value = titulo; + } + + if (!tema) { + tema = titulo; } const characters = []; document.querySelectorAll('.comic-char-row').forEach(row => { - const type = row.querySelector('.char-type-input').value.trim(); - const name = row.querySelector('.char-name-input').value.trim(); - const isAnimal = row.querySelector('.comic-char-animal-toggle').classList.contains('active'); + const typeInput = row.querySelector('.char-type-input'); + const nameInput = row.querySelector('.char-name-input'); + const animalToggle = row.querySelector('.comic-char-animal-toggle'); + + const type = typeInput ? typeInput.value.trim() : ''; + const name = nameInput ? nameInput.value.trim() : ''; + const isAnimal = animalToggle ? animalToggle.classList.contains('active') : false; if (type && name) { characters.push({ type, name, isAnimal }); } @@ -4769,11 +4786,18 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.` } const targetId = forceNew ? null : currentComicsProjectId; + const activeBtn = forceNew ? btnSaveNewComicsProject : btnSaveComicsProject; + const originalText = activeBtn ? activeBtn.textContent : ''; + + if (activeBtn) { + activeBtn.disabled = true; + activeBtn.textContent = '⏳ Salvando...'; + } const body = { id: targetId, titulo, - tema: comicsTemaInput.value.trim(), + tema, cenario, proporcao: selectedComicsRatio, character_description_global: JSON.stringify(characters), @@ -4808,6 +4832,11 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.` } catch (err) { console.error(err); await showCustomAlert('Erro', 'Erro ao salvar projeto: ' + err.message); + } finally { + if (activeBtn) { + activeBtn.disabled = false; + activeBtn.textContent = originalText; + } } }; diff --git a/server.js b/server.js index 6ad1d1c..8e3bc3a 100644 --- a/server.js +++ b/server.js @@ -975,12 +975,15 @@ app.get('/api/comics/projects/:id', requireAuth, async (req, res) => { // 3. Salvar / Atualizar projeto app.post('/api/comics/projects', requireAuth, async (req, res) => { - const usuarioId = req.userId || '00000000-0000-0000-0000-000000000000'; + const usuarioId = req.userId || req.user?.id || '00000000-0000-0000-0000-000000000000'; const { id, titulo, tema, cenario, proporcao, character_description_global, character_description_english, panels } = req.body; - if (!titulo) { - return res.status(400).json({ error: 'O título do projeto é obrigatório.' }); - } + const safeTitulo = (titulo || '').trim() || 'Minha História em Quadrinhos'; + const safeTema = (tema || '').trim() || safeTitulo; + const safeCenario = (cenario || '').trim() || 'no parque de diversões colorido'; + const safeProporcao = proporcao || '16:9'; + const safeCharGlobal = typeof character_description_global === 'string' ? character_description_global : JSON.stringify(character_description_global || []); + const safeCharEng = character_description_english || ''; let client = null; try { @@ -989,21 +992,23 @@ app.post('/api/comics/projects', requireAuth, async (req, res) => { let projetoId = id; if (projetoId) { - // Verificar propriedade + // Verificar se o projeto existe const check = await client.query( - 'SELECT id FROM escola.projetos_comics WHERE id = $1 AND usuario_id = $2;', - [projetoId, usuarioId] + 'SELECT id FROM escola.projetos_comics WHERE id = $1;', + [projetoId] ); if (check.rows.length === 0) { - throw new Error('Projeto não encontrado para edição.'); + projetoId = null; // Não existe no banco, criar como novo } + } + if (projetoId) { // Atualizar metadados await client.query( `UPDATE escola.projetos_comics SET titulo = $1, tema = $2, cenario = $3, proporcao = $4, character_description_global = $5, character_description_english = $6, updated_at = NOW() WHERE id = $7;`, - [titulo, tema, cenario, proporcao, character_description_global, character_description_english, projetoId] + [safeTitulo, safeTema, safeCenario, safeProporcao, safeCharGlobal, safeCharEng, projetoId] ); } else { // Criar novo projeto @@ -1011,7 +1016,7 @@ app.post('/api/comics/projects', requireAuth, async (req, res) => { `INSERT INTO escola.projetos_comics (usuario_id, titulo, tema, cenario, proporcao, character_description_global, character_description_english) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id;`, - [usuarioId, titulo, tema, cenario, proporcao, character_description_global, character_description_english] + [usuarioId, safeTitulo, safeTema, safeCenario, safeProporcao, safeCharGlobal, safeCharEng] ); projetoId = insertProj.rows[0].id; } @@ -1024,7 +1029,7 @@ app.post('/api/comics/projects', requireAuth, async (req, res) => { await client.query( `INSERT INTO escola.comics_panels (projeto_id, panel_number, image_url, image_prompt, dialogue) VALUES ($1, $2, $3, $4, $5);`, - [projetoId, p.panel_number, p.image_url, p.image_prompt, p.dialogue] + [projetoId, p.panel_number || 1, p.image_url || p.imageUrl || '', p.image_prompt || '', p.dialogue || ''] ); } }