From 0f296c854471601a2afb323af4b24853c954bb58 Mon Sep 17 00:00:00 2001 From: admtracksteel Date: Thu, 3 Sep 2026 11:55:14 +0000 Subject: [PATCH] =?UTF-8?q?Corre=C3=A7=C3=A3o=20dos=20bot=C3=B5es=20Protoc?= =?UTF-8?q?olo=20de=20Crise,=20Stickers=20&=20Conquistas=20e=20Atas=20de?= =?UTF-8?q?=20Reuni=C3=A3o=20com=20carregamento=20seguro=20de=20turmas=20e?= =?UTF-8?q?=20autentica=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/app.js | 290 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 199 insertions(+), 91 deletions(-) diff --git a/public/app.js b/public/app.js index f5dfa88..c8de009 100644 --- a/public/app.js +++ b/public/app.js @@ -1,6 +1,27 @@ // Configuração do Markdown parser personalizado com Highlight.js integrado const renderer = new marked.Renderer(); +// Estado global de turmas acessível em todos os módulos +window.currentTurmas = []; +window.getGlobalTurmas = async function() { + if (Array.isArray(window.currentTurmas) && window.currentTurmas.length > 0) { + return window.currentTurmas; + } + try { + const token = localStorage.getItem('token'); + const res = await fetch('/api/turmas', { + headers: token ? { 'Authorization': `Bearer ${token}` } : {} + }); + if (res.ok) { + window.currentTurmas = await res.json(); + return window.currentTurmas; + } + } catch(e) { + console.error('[getGlobalTurmas]', e); + } + return []; +}; + // Função auxiliar para escapar caracteres HTML function escapeHtml(text) { return text @@ -3051,6 +3072,7 @@ const initApp = () => { try { const res = await fetch('/api/turmas'); currentTurmas = await res.json(); + window.currentTurmas = currentTurmas; populateTurmaSelects(); return currentTurmas; } catch(e) { console.error(e); return []; } @@ -11343,7 +11365,15 @@ document.addEventListener('DOMContentLoaded', () => { // ========================================================================== // MÓDULOS EXPANDIDOS: DOSSIÊ DO ALUNO, PROTOCOLO DE CRISES, ATAS & STICKERS // ========================================================================== -document.addEventListener('DOMContentLoaded', () => { +function initExpandedModules() { + + const getAuthHeaders = () => { + const token = localStorage.getItem('token'); + return { + 'Content-Type': 'application/json', + ...(token ? { 'Authorization': `Bearer ${token}` } : {}) + }; + }; // ------------------------------------------------------------------------ // 1. DOSSIÊ & LINHA DO TEMPO DO ALUNO @@ -11356,21 +11386,31 @@ document.addEventListener('DOMContentLoaded', () => { const btnExportFichaConselho = document.getElementById('btnExportFichaConselho'); let currentTimelineAlunoId = null; - if (btnCloseAlunoTimeline) btnCloseAlunoTimeline.addEventListener('click', () => alunoTimelineModal.style.display = 'none'); + if (btnCloseAlunoTimeline) { + btnCloseAlunoTimeline.addEventListener('click', () => { + if (alunoTimelineModal) alunoTimelineModal.style.display = 'none'; + }); + } window.viewChildTimeline = async (alunoId) => { currentTimelineAlunoId = alunoId; - alunoTimelineModal.style.display = 'flex'; - timelineContentArea.innerHTML = '

Carregando dossiê...

'; + if (alunoTimelineModal) alunoTimelineModal.style.display = 'flex'; + if (timelineContentArea) { + timelineContentArea.innerHTML = '

Carregando dossiê do aluno...

'; + } try { - const res = await fetch(`/api/alunos/${alunoId}/timeline`); + const res = await fetch(`/api/alunos/${alunoId}/timeline`, { headers: getAuthHeaders() }); const data = await res.json(); - if (!res.ok) throw new Error(data.error || 'Erro ao carregar dados'); + if (!res.ok) throw new Error(data.error || 'Erro ao carregar dados do aluno'); const aluno = data.aluno; - timelineAlunoNome.textContent = `Dossiê: ${aluno.nome} ${aluno.especial ? '⭐ (Ed. Especial)' : ''}`; - timelineAlunoInfo.textContent = `Nasc: ${aluno.data_nasc ? new Date(aluno.data_nasc).toLocaleDateString('pt-BR') : 'Não informada'} • Pais: ${aluno.pais || 'Não informados'} • Saúde: ${aluno.observacoes_saude || 'Nenhuma alergia/restrição'}`; + if (timelineAlunoNome) { + timelineAlunoNome.textContent = `Dossiê: ${aluno.nome} ${aluno.especial ? '⭐ (Ed. Especial)' : ''}`; + } + if (timelineAlunoInfo) { + timelineAlunoInfo.textContent = `Nasc: ${aluno.data_nasc ? new Date(aluno.data_nasc).toLocaleDateString('pt-BR') : 'Não informada'} • Pais: ${aluno.pais || 'Não informados'} • Saúde: ${aluno.observacoes_saude || 'Nenhuma alergia/restrição'}`; + } let html = ''; @@ -11385,7 +11425,7 @@ document.addEventListener('DOMContentLoaded', () => {
📅 ${o.date || ''} ${o.time || ''} - ${o.tags ? `🏷️ ${o.tags}` : ''} + ${o.tags ? `🏷️ ${escapeHtml(o.tags)}` : ''}

${escapeHtml(o.report || '')}

@@ -11419,7 +11459,7 @@ document.addEventListener('DOMContentLoaded', () => { html += `
${escapeHtml(h.titulo || h.tema)} -
${h.faixa_etaria} • ${new Date(h.created_at).toLocaleDateString('pt-BR')}
+
${h.faixa_etaria || ''} • ${new Date(h.created_at).toLocaleDateString('pt-BR')}
`; }); @@ -11433,7 +11473,7 @@ document.addEventListener('DOMContentLoaded', () => { html += `
- ${escapeHtml(cr.tipo_evento)} (${cr.intensidade}) + ${escapeHtml(cr.tipo_evento)} (${escapeHtml(cr.intensidade)}) ${new Date(cr.data_hora).toLocaleString('pt-BR')}

${escapeHtml(cr.descricao)}

@@ -11450,16 +11490,16 @@ document.addEventListener('DOMContentLoaded', () => { rels.forEach(r => { html += `
- ${r.semestre}º Semestre de ${r.ano_letivo} (${r.faixa_etaria}) + ${r.semestre}º Semestre de ${r.ano_letivo} (${r.faixa_etaria || ''})

${escapeHtml(r.conteudo_relatorio)}

`; }); } - timelineContentArea.innerHTML = html; + if (timelineContentArea) timelineContentArea.innerHTML = html; } catch (err) { - timelineContentArea.innerHTML = `

Erro: ${err.message}

`; + if (timelineContentArea) timelineContentArea.innerHTML = `

Erro: ${err.message}

`; } }; @@ -11468,7 +11508,7 @@ document.addEventListener('DOMContentLoaded', () => { btnExportFichaConselho.addEventListener('click', async () => { if (!currentTimelineAlunoId) return; try { - const res = await fetch(`/api/alunos/${currentTimelineAlunoId}/conselho-ficha`); + const res = await fetch(`/api/alunos/${currentTimelineAlunoId}/conselho-ficha`, { headers: getAuthHeaders() }); const data = await res.json(); if (!res.ok) throw new Error(data.error || 'Falha ao buscar ficha'); @@ -11492,16 +11532,16 @@ document.addEventListener('DOMContentLoaded', () => {

📋 Ficha Individual de Acompanhamento / Conselho de Classe

-
Aluno(a): ${aluno.nome}
-
Turma: ${aluno.turma_nome || 'N/A'}
+
Aluno(a): ${escapeHtml(aluno.nome)}
+
Turma: ${escapeHtml(aluno.turma_nome || 'N/A')}
Data Nasc: ${aluno.data_nasc ? new Date(aluno.data_nasc).toLocaleDateString('pt-BR') : 'N/A'}
-
Educação Especial: ${aluno.especial ? 'Sim (' + (aluno.especial_detalhes || '') + ')' : 'Não'}
-
Total de Observações: ${data.totalObservacoes}
-
Emissão: ${data.dataFicha}
+
Educação Especial: ${aluno.especial ? 'Sim (' + escapeHtml(aluno.especial_detalhes || '') + ')' : 'Não'}
+
Total de Observações: ${data.totalObservacoes || 0}
+
Emissão: ${data.dataFicha || new Date().toLocaleDateString('pt-BR')}

🌟 Conquistas Pedagógicas:

___________________________
Professora Titular
@@ -11529,12 +11569,13 @@ document.addEventListener('DOMContentLoaded', () => { if (btnCloseCsvImport) btnCloseCsvImport.addEventListener('click', () => csvImportModal.style.display = 'none'); - // Botão abrir CSV import (se presente na tela de turmas ou sidebar) - window.openCsvImportModal = () => { - csvImportModal.style.display = 'flex'; + window.openCsvImportModal = async () => { + if (csvImportModal) csvImportModal.style.display = 'flex'; if (csvImportTurmaSelect) { - csvImportTurmaSelect.innerHTML = ''; - (currentTurmas || []).forEach(t => { + csvImportTurmaSelect.innerHTML = ''; + const turmas = await window.getGlobalTurmas(); + csvImportTurmaSelect.innerHTML = ''; + turmas.forEach(t => { const opt = document.createElement('option'); opt.value = t.id; opt.textContent = t.nome; @@ -11572,14 +11613,14 @@ document.addEventListener('DOMContentLoaded', () => { try { const res = await fetch('/api/alunos/import-csv', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ turma_id: turmaId, csv_content: csv }) }); const data = await res.json(); if (!res.ok) throw new Error(data.error || 'Erro na importação'); alert(`✅ Sucesso! ${data.count} alunos foram importados para a turma.`); - csvImportModal.style.display = 'none'; + if (csvImportModal) csvImportModal.style.display = 'none'; if (typeof fetchAlunos === 'function') await fetchAlunos(); if (typeof renderAlunosList === 'function') renderAlunosList(); } catch (err) { @@ -11612,10 +11653,12 @@ document.addEventListener('DOMContentLoaded', () => { const btnSendWhatsappDirect = document.getElementById('btnSendWhatsappDirect'); const criseHistoryList = document.getElementById('criseHistoryList'); - function populateCriseTurmas() { + async function populateCriseTurmas() { if (!criseTurmaSelect) return; + criseTurmaSelect.innerHTML = ''; + const turmas = await window.getGlobalTurmas(); criseTurmaSelect.innerHTML = ''; - (currentTurmas || []).forEach(t => { + turmas.forEach(t => { const opt = document.createElement('option'); opt.value = t.id; opt.textContent = t.nome; @@ -11624,50 +11667,66 @@ document.addEventListener('DOMContentLoaded', () => { } if (btnProtocoloCrise) { - btnProtocoloCrise.addEventListener('click', () => { - criseModal.style.display = 'flex'; - populateCriseTurmas(); + btnProtocoloCrise.addEventListener('click', async (e) => { + e.preventDefault(); + e.stopPropagation(); + if (criseModal) criseModal.style.display = 'flex'; + await populateCriseTurmas(); + }); + } + + if (btnCloseCriseModal) { + btnCloseCriseModal.addEventListener('click', () => { + if (criseModal) criseModal.style.display = 'none'; }); } - if (btnCloseCriseModal) btnCloseCriseModal.addEventListener('click', () => criseModal.style.display = 'none'); if (btnOpenCrisesHistory) { btnOpenCrisesHistory.addEventListener('click', async () => { - criseHistoryModal.style.display = 'flex'; + if (criseHistoryModal) criseHistoryModal.style.display = 'flex'; if (!criseHistoryList) return; - criseHistoryList.innerHTML = '

Carregando...

'; + criseHistoryList.innerHTML = '

Carregando histórico...

'; try { - const res = await fetch('/api/crises/list'); + const res = await fetch('/api/crises/list', { headers: getAuthHeaders() }); const data = await res.json(); + if (!res.ok) throw new Error(data.error || 'Erro ao carregar'); if (data.length === 0) { - criseHistoryList.innerHTML = '

Nenhuma ocorrência registrada.

'; + criseHistoryList.innerHTML = '

Nenhuma ocorrência registrada ainda.

'; return; } criseHistoryList.innerHTML = data.map(c => `
- ${escapeHtml(c.aluno_nome)} • ${escapeHtml(c.tipo_evento)} + ${escapeHtml(c.aluno_nome)} • ${escapeHtml(c.tipo_evento)} (${escapeHtml(c.intensidade || 'Moderada')}) ${new Date(c.data_hora).toLocaleString('pt-BR')}

${escapeHtml(c.descricao)}

-
Medidas: ${escapeHtml(c.medidas_tomadas)}
+
Medidas adotadas: ${escapeHtml(c.medidas_tomadas)}
`).join(''); } catch (e) { - criseHistoryList.innerHTML = `

Erro ao carregar: ${e.message}

`; + criseHistoryList.innerHTML = `

Erro: ${e.message}

`; } }); } window.deleteCriseRecord = async (id) => { - if (confirm('Deseja excluir este registro de mediação?')) { - await fetch(`/api/crises/${id}`, { method: 'DELETE' }); - if (btnOpenCrisesHistory) btnOpenCrisesHistory.click(); + if (confirm('Deseja realmente excluir este registro de ocorrência?')) { + try { + await fetch(`/api/crises/${id}`, { method: 'DELETE', headers: getAuthHeaders() }); + if (btnOpenCrisesHistory) btnOpenCrisesHistory.click(); + } catch(e) { + alert('Erro ao excluir: ' + e.message); + } } }; - if (btnCloseCriseHistory) btnCloseCriseHistory.addEventListener('click', () => criseHistoryModal.style.display = 'none'); + if (btnCloseCriseHistory) { + btnCloseCriseHistory.addEventListener('click', () => { + if (criseHistoryModal) criseHistoryModal.style.display = 'none'; + }); + } if (btnSalvarCrise) { btnSalvarCrise.addEventListener('click', async () => { @@ -11689,7 +11748,7 @@ document.addEventListener('DOMContentLoaded', () => { try { const res = await fetch('/api/crises/register', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ aluno_nome: alunoNome, turma_id: turmaId, @@ -11708,7 +11767,7 @@ document.addEventListener('DOMContentLoaded', () => { btnSendWhatsappDirect.href = `https://api.whatsapp.com/send?text=${encodeURIComponent(data.mensagemWhatsapp || '')}`; btnSendWhatsappDirect.style.display = 'block'; } - alert('✅ Protocolo registrado com sucesso! Mensagem para os pais gerada.'); + showToast('✅ Ocorrência registrada e mensagem gerada!', 'success'); } catch (err) { alert('Erro ao registrar crise: ' + err.message); } finally { @@ -11722,7 +11781,7 @@ document.addEventListener('DOMContentLoaded', () => { btnCopyCriseWhatsapp.addEventListener('click', () => { if (criseWhatsappOutput && criseWhatsappOutput.textContent) { navigator.clipboard.writeText(criseWhatsappOutput.textContent); - alert('Mensagem copiada para a área de transferência!'); + showToast('Mensagem copiada para a área de transferência!', 'success'); } }); } @@ -11749,10 +11808,12 @@ document.addEventListener('DOMContentLoaded', () => { const btnPrintAtaPdf = document.getElementById('btnPrintAtaPdf'); const atasHistoryList = document.getElementById('atasHistoryList'); - function populateAtaTurmas() { + async function populateAtaTurmas() { if (!ataTurmaSelect) return; + ataTurmaSelect.innerHTML = ''; + const turmas = await window.getGlobalTurmas(); ataTurmaSelect.innerHTML = ''; - (currentTurmas || []).forEach(t => { + turmas.forEach(t => { const opt = document.createElement('option'); opt.value = t.id; opt.textContent = t.nome; @@ -11761,12 +11822,19 @@ document.addEventListener('DOMContentLoaded', () => { } if (btnAtasReuniao) { - btnAtasReuniao.addEventListener('click', () => { - ataModal.style.display = 'flex'; - populateAtaTurmas(); + btnAtasReuniao.addEventListener('click', async (e) => { + e.preventDefault(); + e.stopPropagation(); + if (ataModal) ataModal.style.display = 'flex'; + await populateAtaTurmas(); + }); + } + + if (btnCloseAtaModal) { + btnCloseAtaModal.addEventListener('click', () => { + if (ataModal) ataModal.style.display = 'none'; }); } - if (btnCloseAtaModal) btnCloseAtaModal.addEventListener('click', () => ataModal.style.display = 'none'); if (btnGerarAta) { btnGerarAta.addEventListener('click', async () => { @@ -11789,7 +11857,7 @@ document.addEventListener('DOMContentLoaded', () => { try { const res = await fetch('/api/atas/generate', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ tipo_reuniao: tipo, titulo: titulo, @@ -11805,7 +11873,7 @@ document.addEventListener('DOMContentLoaded', () => { if (!res.ok) throw new Error(data.error || 'Falha ao redigir ata'); if (ataOutputText) ataOutputText.textContent = data.textoAta || ''; - alert('✅ Ata formal redigida com sucesso!'); + showToast('✅ Ata formal gerada com sucesso!', 'success'); } catch (err) { alert('Erro ao gerar ata: ' + err.message); } finally { @@ -11819,7 +11887,7 @@ document.addEventListener('DOMContentLoaded', () => { btnCopyAta.addEventListener('click', () => { if (ataOutputText && ataOutputText.textContent) { navigator.clipboard.writeText(ataOutputText.textContent); - alert('Ata copiada para a área de transferência!'); + showToast('Texto da ata copiado com sucesso!', 'success'); } }); } @@ -11854,14 +11922,15 @@ document.addEventListener('DOMContentLoaded', () => { if (btnOpenAtasHistory) { btnOpenAtasHistory.addEventListener('click', async () => { - atasHistoryModal.style.display = 'flex'; + if (atasHistoryModal) atasHistoryModal.style.display = 'flex'; if (!atasHistoryList) return; - atasHistoryList.innerHTML = '

Carregando atas...

'; + atasHistoryList.innerHTML = '

Carregando atas...

'; try { - const res = await fetch('/api/atas/list'); + const res = await fetch('/api/atas/list', { headers: getAuthHeaders() }); const data = await res.json(); + if (!res.ok) throw new Error(data.error || 'Erro ao carregar histórico'); if (data.length === 0) { - atasHistoryList.innerHTML = '

Nenhuma ata salva.

'; + atasHistoryList.innerHTML = '

Nenhuma ata salva ainda.

'; return; } atasHistoryList.innerHTML = data.map(a => ` @@ -11874,19 +11943,27 @@ document.addEventListener('DOMContentLoaded', () => {
`).join(''); } catch (e) { - atasHistoryList.innerHTML = `

Erro: ${e.message}

`; + atasHistoryList.innerHTML = `

Erro: ${e.message}

`; } }); } window.deleteAtaRecord = async (id) => { - if (confirm('Deseja excluir esta ata?')) { - await fetch(`/api/atas/${id}`, { method: 'DELETE' }); - if (btnOpenAtasHistory) btnOpenAtasHistory.click(); + if (confirm('Deseja realmente excluir esta ata?')) { + try { + await fetch(`/api/atas/${id}`, { method: 'DELETE', headers: getAuthHeaders() }); + if (btnOpenAtasHistory) btnOpenAtasHistory.click(); + } catch(e) { + alert('Erro ao excluir: ' + e.message); + } } }; - if (btnCloseAtasHistory) btnCloseAtasHistory.addEventListener('click', () => atasHistoryModal.style.display = 'none'); + if (btnCloseAtasHistory) { + btnCloseAtasHistory.addEventListener('click', () => { + if (atasHistoryModal) atasHistoryModal.style.display = 'none'; + }); + } // ------------------------------------------------------------------------ // 5. STICKERS GAMIFICADOS & CARTELA A4 DE IMPRESSÃO @@ -11903,10 +11980,12 @@ document.addEventListener('DOMContentLoaded', () => { const stickersListGrid = document.getElementById('stickersListGrid'); const btnPrintStickerSheet = document.getElementById('btnPrintStickerSheet'); - function populateStickerTurmas() { + async function populateStickerTurmas() { if (!stickerTurmaSelect) return; + stickerTurmaSelect.innerHTML = ''; + const turmas = await window.getGlobalTurmas(); stickerTurmaSelect.innerHTML = ''; - (currentTurmas || []).forEach(t => { + turmas.forEach(t => { const opt = document.createElement('option'); opt.value = t.id; opt.textContent = t.nome; @@ -11916,41 +11995,54 @@ document.addEventListener('DOMContentLoaded', () => { async function loadStickersGrid() { if (!stickersListGrid) return; - stickersListGrid.innerHTML = '

Carregando...

'; + stickersListGrid.innerHTML = '

Carregando conquistas...

'; try { - const res = await fetch('/api/stickers/list'); + const res = await fetch('/api/stickers/list', { headers: getAuthHeaders() }); const data = await res.json(); + if (!res.ok) throw new Error(data.error || 'Erro ao buscar'); if (data.length === 0) { - stickersListGrid.innerHTML = '

Nenhum sticker emitido ainda.

'; + stickersListGrid.innerHTML = '

Nenhum sticker emitido ainda.

'; return; } stickersListGrid.innerHTML = data.map(s => `
${s.icone || '🌟'} - ${escapeHtml(s.titulo)} - ${escapeHtml(s.aluno_nome)} - ${s.qr_code_url ? `` : ''} + ${escapeHtml(s.titulo)} + ${escapeHtml(s.aluno_nome)} + ${escapeHtml(s.categoria || '')} + ${s.qr_code_url ? `` : ''}
`).join(''); } catch (e) { - stickersListGrid.innerHTML = `

Erro: ${e.message}

`; + stickersListGrid.innerHTML = `

Erro: ${e.message}

`; } } if (btnStickersConquistas) { - btnStickersConquistas.addEventListener('click', () => { - stickerModal.style.display = 'flex'; - populateStickerTurmas(); - loadStickersGrid(); + btnStickersConquistas.addEventListener('click', async (e) => { + e.preventDefault(); + e.stopPropagation(); + if (stickerModal) stickerModal.style.display = 'flex'; + await populateStickerTurmas(); + await loadStickersGrid(); + }); + } + + if (btnCloseStickerModal) { + btnCloseStickerModal.addEventListener('click', () => { + if (stickerModal) stickerModal.style.display = 'none'; }); } - if (btnCloseStickerModal) btnCloseStickerModal.addEventListener('click', () => stickerModal.style.display = 'none'); window.deleteStickerRecord = async (id) => { - if (confirm('Deseja excluir este sticker?')) { - await fetch(`/api/stickers/${id}`, { method: 'DELETE' }); - loadStickersGrid(); + if (confirm('Deseja realmente excluir este sticker?')) { + try { + await fetch(`/api/stickers/${id}`, { method: 'DELETE', headers: getAuthHeaders() }); + await loadStickersGrid(); + } catch(e) { + alert('Erro ao excluir: ' + e.message); + } } }; @@ -11963,7 +12055,7 @@ document.addEventListener('DOMContentLoaded', () => { const turmaId = stickerTurmaSelect ? stickerTurmaSelect.value : null; if (!alunoNome || !titulo || !desc) { - alert('Por favor, informe a criança, o título da conquista e a descrição.'); + alert('Por favor, informe o nome da criança, o título da conquista e a descrição.'); return; } @@ -11976,9 +12068,12 @@ document.addEventListener('DOMContentLoaded', () => { else if (cat.includes('Roda')) icone = '🗣️'; try { + btnEmitirSticker.disabled = true; + btnEmitirSticker.textContent = '⏳ Emitindo...'; + const res = await fetch('/api/stickers/create', { method: 'POST', - headers: { 'Content-Type': 'application/json' }, + headers: getAuthHeaders(), body: JSON.stringify({ aluno_nome: alunoNome, turma_id: turmaId, @@ -11990,10 +12085,16 @@ document.addEventListener('DOMContentLoaded', () => { }); const data = await res.json(); if (!res.ok) throw new Error(data.error || 'Falha ao emitir sticker'); - alert('✅ Conquista registrada com sucesso!'); - loadStickersGrid(); + showToast('✅ Conquista emitida com sucesso!', 'success'); + if (stickerAlunoInput) stickerAlunoInput.value = ''; + if (stickerTituloInput) stickerTituloInput.value = ''; + if (stickerDescricaoInput) stickerDescricaoInput.value = ''; + await loadStickersGrid(); } catch (err) { alert('Erro: ' + err.message); + } finally { + btnEmitirSticker.disabled = false; + btnEmitirSticker.textContent = '🏅 Emitir Conquista'; } }); } @@ -12002,9 +12103,9 @@ document.addEventListener('DOMContentLoaded', () => { if (btnPrintStickerSheet) { btnPrintStickerSheet.addEventListener('click', async () => { try { - const res = await fetch('/api/stickers/list'); + const res = await fetch('/api/stickers/list', { headers: getAuthHeaders() }); const stickers = await res.json(); - if (stickers.length === 0) { + if (!res.ok || !stickers || stickers.length === 0) { alert('Emita ao menos um sticker antes de imprimir a cartela.'); return; } @@ -12018,7 +12119,7 @@ document.addEventListener('DOMContentLoaded', () => { ${escapeHtml(s.titulo)}
${escapeHtml(s.aluno_nome)}

${escapeHtml(s.descricao)}

- ${s.qr_code_url ? `` : ''} + ${s.qr_code_url ? `` : ''}
Pedagog • Conquista Escolar
`; @@ -12053,5 +12154,12 @@ document.addEventListener('DOMContentLoaded', () => { }); } -}); +} + +// Inicialização com fallback para carregamento dinâmico ou DOMContentLoaded +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initExpandedModules); +} else { + initExpandedModules(); +}