Corrigir exclusao e salvamento de projetos com dialogos customizados e botao duplo salvar
This commit is contained in:
+114
-21
@@ -11,6 +11,72 @@ function escapeHtml(text) {
|
|||||||
.replace(/'/g, "'");
|
.replace(/'/g, "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Função auxiliar para exibir alerta customizado e elegante (substitui o alert nativo)
|
||||||
|
function showCustomAlert(title, message) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const overlay = document.createElement('div');
|
||||||
|
overlay.className = 'custom-dialog-overlay';
|
||||||
|
|
||||||
|
overlay.innerHTML = `
|
||||||
|
<div class="custom-dialog-card">
|
||||||
|
<div class="custom-dialog-header">
|
||||||
|
<span>🔔</span>
|
||||||
|
<span>${escapeHtml(title)}</span>
|
||||||
|
</div>
|
||||||
|
<p class="custom-dialog-body">${escapeHtml(message)}</p>
|
||||||
|
<div class="custom-dialog-footer">
|
||||||
|
<button class="btn-dialog btn-dialog-confirm">OK</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const btn = overlay.querySelector('.btn-dialog-confirm');
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
overlay.remove();
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Função auxiliar para exibir diálogo de confirmação elegante (substitui o confirm nativo)
|
||||||
|
function showCustomConfirm(title, message, isDanger = false) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const overlay = document.createElement('div');
|
||||||
|
overlay.className = 'custom-dialog-overlay';
|
||||||
|
|
||||||
|
overlay.innerHTML = `
|
||||||
|
<div class="custom-dialog-card">
|
||||||
|
<div class="custom-dialog-header">
|
||||||
|
<span>${isDanger ? '⚠️' : '❓'}</span>
|
||||||
|
<span>${escapeHtml(title)}</span>
|
||||||
|
</div>
|
||||||
|
<p class="custom-dialog-body">${escapeHtml(message)}</p>
|
||||||
|
<div class="custom-dialog-footer">
|
||||||
|
<button class="btn-dialog btn-dialog-cancel">Cancelar</button>
|
||||||
|
<button class="btn-dialog ${isDanger ? 'btn-dialog-danger' : 'btn-dialog-confirm'}">${isDanger ? 'Excluir' : 'Confirmar'}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const btnCancel = overlay.querySelector('.btn-dialog-cancel');
|
||||||
|
const btnConfirm = overlay.querySelector(isDanger ? '.btn-dialog-danger' : '.btn-dialog-confirm');
|
||||||
|
|
||||||
|
btnCancel.addEventListener('click', () => {
|
||||||
|
overlay.remove();
|
||||||
|
resolve(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
btnConfirm.addEventListener('click', () => {
|
||||||
|
overlay.remove();
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Função auxiliar para gerar nome de arquivo de download formatado como <nome_data_hora>.<extensao>
|
// Função auxiliar para gerar nome de arquivo de download formatado como <nome_data_hora>.<extensao>
|
||||||
function getDownloadFileName(type, ext) {
|
function getDownloadFileName(type, ext) {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
@@ -3504,6 +3570,7 @@ const initApp = () => {
|
|||||||
const btnDeleteComicsProject = document.getElementById('btnDeleteComicsProject');
|
const btnDeleteComicsProject = document.getElementById('btnDeleteComicsProject');
|
||||||
const comicsProjectTitleInput = document.getElementById('comicsProjectTitleInput');
|
const comicsProjectTitleInput = document.getElementById('comicsProjectTitleInput');
|
||||||
const btnSaveComicsProject = document.getElementById('btnSaveComicsProject');
|
const btnSaveComicsProject = document.getElementById('btnSaveComicsProject');
|
||||||
|
const btnSaveNewComicsProject = document.getElementById('btnSaveNewComicsProject');
|
||||||
|
|
||||||
let currentComicsProjectId = null;
|
let currentComicsProjectId = null;
|
||||||
let currentComicsCharDescEnglish = '';
|
let currentComicsCharDescEnglish = '';
|
||||||
@@ -3619,6 +3686,7 @@ const initApp = () => {
|
|||||||
if (comicsProjectSelect) comicsProjectSelect.value = '';
|
if (comicsProjectSelect) comicsProjectSelect.value = '';
|
||||||
if (comicsProjectTitleInput) comicsProjectTitleInput.value = '';
|
if (comicsProjectTitleInput) comicsProjectTitleInput.value = '';
|
||||||
if (btnDeleteComicsProject) btnDeleteComicsProject.style.display = 'none';
|
if (btnDeleteComicsProject) btnDeleteComicsProject.style.display = 'none';
|
||||||
|
if (btnSaveComicsProject) btnSaveComicsProject.style.display = 'none';
|
||||||
|
|
||||||
comicsTemaInput.value = '';
|
comicsTemaInput.value = '';
|
||||||
comicsResultArea.style.display = 'none';
|
comicsResultArea.style.display = 'none';
|
||||||
@@ -3707,6 +3775,7 @@ const initApp = () => {
|
|||||||
comicsTemaInput.value = project.tema || '';
|
comicsTemaInput.value = project.tema || '';
|
||||||
|
|
||||||
if (btnDeleteComicsProject) btnDeleteComicsProject.style.display = 'block';
|
if (btnDeleteComicsProject) btnDeleteComicsProject.style.display = 'block';
|
||||||
|
if (btnSaveComicsProject) btnSaveComicsProject.style.display = 'block';
|
||||||
|
|
||||||
// Carregar proporção
|
// Carregar proporção
|
||||||
selectedComicsRatio = project.proporcao || '16:9';
|
selectedComicsRatio = project.proporcao || '16:9';
|
||||||
@@ -3829,34 +3898,40 @@ const initApp = () => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert('Erro ao carregar projeto: ' + err.message);
|
await showCustomAlert('Erro', 'Erro ao carregar projeto: ' + err.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveComicsProject = async () => {
|
const saveComicsProjectFlow = async (forceNew = false) => {
|
||||||
const titulo = comicsProjectTitleInput ? comicsProjectTitleInput.value.trim() : '';
|
const titulo = comicsProjectTitleInput ? comicsProjectTitleInput.value.trim() : '';
|
||||||
if (!titulo) {
|
if (!titulo) {
|
||||||
alert('Por favor, digite um título para salvar seu projeto.');
|
await showCustomAlert('Campo Obrigatório', 'Por favor, digite um título para salvar seu projeto.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const characters = [];
|
const characters = [];
|
||||||
document.querySelectorAll('.comic-char-row').forEach(row => {
|
document.querySelectorAll('.comic-char-row').forEach(row => {
|
||||||
const type = row.querySelector('.char-type-input').value.trim();
|
const typeInput = row.querySelector('.char-type-input');
|
||||||
const name = row.querySelector('.char-name-input').value.trim();
|
const nameInput = row.querySelector('.char-name-input');
|
||||||
const isAnimal = row.querySelector('span').textContent === '🐾';
|
if (typeInput && nameInput) {
|
||||||
if (type || name) {
|
const type = typeInput.value.trim();
|
||||||
characters.push({ type, name, isAnimal });
|
const name = nameInput.value.trim();
|
||||||
|
const isAnimal = row.querySelector('span').textContent === '🐾';
|
||||||
|
if (type || name) {
|
||||||
|
characters.push({ type, name, isAnimal });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let cenario = comicsCenarioSelect.value;
|
let cenario = comicsCenarioSelect ? comicsCenarioSelect.value : 'no parque de diversões colorido';
|
||||||
if (cenario === 'custom') {
|
if (cenario === 'custom' && comicsCenarioCustomInput) {
|
||||||
cenario = comicsCenarioCustomInput.value.trim();
|
cenario = comicsCenarioCustomInput.value.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const targetId = forceNew ? null : currentComicsProjectId;
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
id: currentComicsProjectId,
|
id: targetId,
|
||||||
titulo,
|
titulo,
|
||||||
tema: comicsTemaInput.value.trim(),
|
tema: comicsTemaInput.value.trim(),
|
||||||
cenario,
|
cenario,
|
||||||
@@ -3885,18 +3960,28 @@ const initApp = () => {
|
|||||||
|
|
||||||
const data = await resp.json();
|
const data = await resp.json();
|
||||||
currentComicsProjectId = data.id;
|
currentComicsProjectId = data.id;
|
||||||
alert('Projeto salvo com sucesso!');
|
await showCustomAlert('Sucesso', 'Projeto salvo com sucesso!');
|
||||||
|
|
||||||
if (btnDeleteComicsProject) btnDeleteComicsProject.style.display = 'block';
|
if (btnDeleteComicsProject) btnDeleteComicsProject.style.display = 'block';
|
||||||
|
if (btnSaveComicsProject) btnSaveComicsProject.style.display = 'block';
|
||||||
await loadComicsProjectsList();
|
await loadComicsProjectsList();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert('Erro ao salvar projeto: ' + err.message);
|
await showCustomAlert('Erro', 'Erro ao salvar projeto: ' + err.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const saveComicsProject = () => saveComicsProjectFlow(false);
|
||||||
|
const saveNewComicsProject = () => saveComicsProjectFlow(true);
|
||||||
|
|
||||||
const deleteComicsProject = async () => {
|
const deleteComicsProject = async () => {
|
||||||
if (!currentComicsProjectId) return;
|
if (!currentComicsProjectId) return;
|
||||||
if (!confirm('Tem certeza de que deseja excluir este projeto permanentemente?')) return;
|
const confirmed = await showCustomConfirm(
|
||||||
|
'Confirmar Exclusão',
|
||||||
|
'Tem certeza de que deseja excluir este projeto permanentemente?',
|
||||||
|
true
|
||||||
|
);
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await fetch(`/api/comics/projects/${currentComicsProjectId}`, {
|
const resp = await fetch(`/api/comics/projects/${currentComicsProjectId}`, {
|
||||||
@@ -3905,12 +3990,12 @@ const initApp = () => {
|
|||||||
|
|
||||||
if (!resp.ok) throw new Error('Falha ao excluir projeto');
|
if (!resp.ok) throw new Error('Falha ao excluir projeto');
|
||||||
|
|
||||||
alert('Projeto excluído com sucesso!');
|
await showCustomAlert('Excluído', 'Projeto excluído com sucesso!');
|
||||||
startNewComicsProject();
|
startNewComicsProject();
|
||||||
await loadComicsProjectsList();
|
await loadComicsProjectsList();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
alert('Erro ao excluir projeto: ' + err.message);
|
await showCustomAlert('Erro', 'Erro ao excluir projeto: ' + err.message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3929,8 +4014,12 @@ const initApp = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (btnNewComicsProject) {
|
if (btnNewComicsProject) {
|
||||||
btnNewComicsProject.addEventListener('click', () => {
|
btnNewComicsProject.addEventListener('click', async () => {
|
||||||
if (confirm('Deseja iniciar um novo projeto? Alterações não salvas serão perdidas.')) {
|
const confirmed = await showCustomConfirm(
|
||||||
|
'Novo Projeto',
|
||||||
|
'Deseja iniciar um novo projeto? Alterações não salvas serão perdidas.'
|
||||||
|
);
|
||||||
|
if (confirmed) {
|
||||||
startNewComicsProject();
|
startNewComicsProject();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -3940,6 +4029,10 @@ const initApp = () => {
|
|||||||
btnSaveComicsProject.addEventListener('click', saveComicsProject);
|
btnSaveComicsProject.addEventListener('click', saveComicsProject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (btnSaveNewComicsProject) {
|
||||||
|
btnSaveNewComicsProject.addEventListener('click', saveNewComicsProject);
|
||||||
|
}
|
||||||
|
|
||||||
if (btnDeleteComicsProject) {
|
if (btnDeleteComicsProject) {
|
||||||
btnDeleteComicsProject.addEventListener('click', deleteComicsProject);
|
btnDeleteComicsProject.addEventListener('click', deleteComicsProject);
|
||||||
}
|
}
|
||||||
@@ -3986,7 +4079,7 @@ const initApp = () => {
|
|||||||
btnGenerateComics.addEventListener('click', async () => {
|
btnGenerateComics.addEventListener('click', async () => {
|
||||||
const tema = comicsTemaInput.value.trim();
|
const tema = comicsTemaInput.value.trim();
|
||||||
if (!tema) {
|
if (!tema) {
|
||||||
alert('Por favor, digite um tema para a história.');
|
await showCustomAlert('Campo Requerido', 'Por favor, digite um tema para a história.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4001,7 +4094,7 @@ const initApp = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (personagens.length === 0) {
|
if (personagens.length === 0) {
|
||||||
alert('Adicione e preencha pelo menos um personagem principal.');
|
await showCustomAlert('Personagens Faltando', 'Adicione e preencha pelo menos um personagem principal.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4161,7 +4254,7 @@ const initApp = () => {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Erro ao fabricar quadrinhos:', err);
|
console.error('Erro ao fabricar quadrinhos:', err);
|
||||||
alert('Erro ao fabricar quadrinhos: ' + err.message);
|
await showCustomAlert('Erro', 'Erro ao fabricar quadrinhos: ' + err.message);
|
||||||
comicsGenerateLoader.style.display = 'none';
|
comicsGenerateLoader.style.display = 'none';
|
||||||
btnGenerateComics.disabled = false;
|
btnGenerateComics.disabled = false;
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -759,7 +759,8 @@
|
|||||||
|
|
||||||
<div style="display: flex; align-items: center; gap: 10px;">
|
<div style="display: flex; align-items: center; gap: 10px;">
|
||||||
<input type="text" id="comicsProjectTitleInput" class="obs-input" placeholder="Título do Projeto (Ex: Lucas e Mariana no Parque)" style="flex: 1; margin: 0; padding: 8px 12px; font-size: 0.9rem;">
|
<input type="text" id="comicsProjectTitleInput" class="obs-input" placeholder="Título do Projeto (Ex: Lucas e Mariana no Parque)" style="flex: 1; margin: 0; padding: 8px 12px; font-size: 0.9rem;">
|
||||||
<button type="button" id="btnSaveComicsProject" class="btn-music-option" style="padding: 8px 14px; font-size: 0.82rem; border-color: #10a37f; color: white; background: #10a37f; margin: 0; white-space: nowrap; font-weight: 600;">💾 Salvar</button>
|
<button type="button" id="btnSaveComicsProject" class="btn-music-option" style="padding: 8px 14px; font-size: 0.82rem; border-color: #10a37f; color: white; background: #10a37f; margin: 0; white-space: nowrap; font-weight: 600; display: none;">💾 Salvar Alterações</button>
|
||||||
|
<button type="button" id="btnSaveNewComicsProject" class="btn-music-option" style="padding: 8px 14px; font-size: 0.82rem; border-color: var(--brand-pink); color: white; background: var(--brand-pink); margin: 0; white-space: nowrap; font-weight: 600;">💾 Salvar como Novo</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- MODO DE CONTINUIDADE (Apenas quando um projeto é carregado) -->
|
<!-- MODO DE CONTINUIDADE (Apenas quando um projeto é carregado) -->
|
||||||
|
|||||||
@@ -3231,5 +3231,117 @@ code {
|
|||||||
box-shadow: 0 0 8px rgba(219, 39, 119, 0.2);
|
box-shadow: 0 0 8px rgba(219, 39, 119, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
CUSTOM MODAL DIALOGS (ALERT & CONFIRM)
|
||||||
|
========================================================================== */
|
||||||
|
.custom-dialog-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 10000;
|
||||||
|
animation: dialogFadeIn 0.2s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dialog-card {
|
||||||
|
background: var(--bg-primary, #121212);
|
||||||
|
border: 1px solid var(--border-light, #262626);
|
||||||
|
border-radius: 16px;
|
||||||
|
width: 400px;
|
||||||
|
max-width: 90%;
|
||||||
|
padding: 24px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
transform: scale(0.9);
|
||||||
|
opacity: 0;
|
||||||
|
animation: dialogScaleUp 0.25s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dialog-header {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-primary, #ffffff);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dialog-body {
|
||||||
|
font-size: 0.92rem;
|
||||||
|
color: var(--text-secondary, #a3a3a3);
|
||||||
|
line-height: 1.5;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-dialog-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-dialog {
|
||||||
|
padding: 8px 18px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-dialog-cancel {
|
||||||
|
background: transparent;
|
||||||
|
border-color: var(--border-light, #262626);
|
||||||
|
color: var(--text-secondary, #a3a3a3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-dialog-cancel:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
color: var(--text-primary, #ffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-dialog-confirm {
|
||||||
|
background: linear-gradient(135deg, var(--brand-green, #10a37f) 0%, #0a5f49 100%);
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 4px 12px rgba(16, 163, 127, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-dialog-confirm:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-dialog-danger {
|
||||||
|
background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%);
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 4px 12px rgba(239, 68, 68, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-dialog-danger:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dialogFadeIn {
|
||||||
|
from { opacity: 0; }
|
||||||
|
to { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dialogScaleUp {
|
||||||
|
from { transform: scale(0.95); opacity: 0; }
|
||||||
|
to { transform: scale(1); opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user