Correção dos botões Protocolo de Crise, Stickers & Conquistas e Atas de Reunião com carregamento seguro de turmas e autenticação
This commit is contained in:
+199
-91
@@ -1,6 +1,27 @@
|
|||||||
// Configuração do Markdown parser personalizado com Highlight.js integrado
|
// Configuração do Markdown parser personalizado com Highlight.js integrado
|
||||||
const renderer = new marked.Renderer();
|
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
|
// Função auxiliar para escapar caracteres HTML
|
||||||
function escapeHtml(text) {
|
function escapeHtml(text) {
|
||||||
return text
|
return text
|
||||||
@@ -3051,6 +3072,7 @@ const initApp = () => {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch('/api/turmas');
|
const res = await fetch('/api/turmas');
|
||||||
currentTurmas = await res.json();
|
currentTurmas = await res.json();
|
||||||
|
window.currentTurmas = currentTurmas;
|
||||||
populateTurmaSelects();
|
populateTurmaSelects();
|
||||||
return currentTurmas;
|
return currentTurmas;
|
||||||
} catch(e) { console.error(e); return []; }
|
} catch(e) { console.error(e); return []; }
|
||||||
@@ -11343,7 +11365,15 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// MÓDULOS EXPANDIDOS: DOSSIÊ DO ALUNO, PROTOCOLO DE CRISES, ATAS & STICKERS
|
// 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
|
// 1. DOSSIÊ & LINHA DO TEMPO DO ALUNO
|
||||||
@@ -11356,21 +11386,31 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const btnExportFichaConselho = document.getElementById('btnExportFichaConselho');
|
const btnExportFichaConselho = document.getElementById('btnExportFichaConselho');
|
||||||
let currentTimelineAlunoId = null;
|
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) => {
|
window.viewChildTimeline = async (alunoId) => {
|
||||||
currentTimelineAlunoId = alunoId;
|
currentTimelineAlunoId = alunoId;
|
||||||
alunoTimelineModal.style.display = 'flex';
|
if (alunoTimelineModal) alunoTimelineModal.style.display = 'flex';
|
||||||
timelineContentArea.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Carregando dossiê...</p>';
|
if (timelineContentArea) {
|
||||||
|
timelineContentArea.innerHTML = '<p style="text-align:center; color:var(--text-secondary); padding:20px;">Carregando dossiê do aluno...</p>';
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/alunos/${alunoId}/timeline`);
|
const res = await fetch(`/api/alunos/${alunoId}/timeline`, { headers: getAuthHeaders() });
|
||||||
const data = await res.json();
|
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;
|
const aluno = data.aluno;
|
||||||
timelineAlunoNome.textContent = `Dossiê: ${aluno.nome} ${aluno.especial ? '⭐ (Ed. Especial)' : ''}`;
|
if (timelineAlunoNome) {
|
||||||
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'}`;
|
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 = '';
|
let html = '';
|
||||||
|
|
||||||
@@ -11385,7 +11425,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
<div style="background:rgba(244,63,94,0.05); border-left:3px solid #f43f5e; padding:8px 12px; border-radius:4px; font-size:0.82rem; margin-bottom:6px;">
|
<div style="background:rgba(244,63,94,0.05); border-left:3px solid #f43f5e; padding:8px 12px; border-radius:4px; font-size:0.82rem; margin-bottom:6px;">
|
||||||
<div style="display:flex; justify-content:space-between; color:var(--text-secondary); font-size:0.75rem;">
|
<div style="display:flex; justify-content:space-between; color:var(--text-secondary); font-size:0.75rem;">
|
||||||
<strong>📅 ${o.date || ''} ${o.time || ''}</strong>
|
<strong>📅 ${o.date || ''} ${o.time || ''}</strong>
|
||||||
${o.tags ? `<span>🏷️ ${o.tags}</span>` : ''}
|
${o.tags ? `<span>🏷️ ${escapeHtml(o.tags)}</span>` : ''}
|
||||||
</div>
|
</div>
|
||||||
<p style="margin:4px 0 0 0; color:var(--text-primary);">${escapeHtml(o.report || '')}</p>
|
<p style="margin:4px 0 0 0; color:var(--text-primary);">${escapeHtml(o.report || '')}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -11419,7 +11459,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
html += `
|
html += `
|
||||||
<div style="background:rgba(16,185,129,0.05); border-left:3px solid #10b981; padding:8px 12px; border-radius:4px; font-size:0.82rem; margin-bottom:6px;">
|
<div style="background:rgba(16,185,129,0.05); border-left:3px solid #10b981; padding:8px 12px; border-radius:4px; font-size:0.82rem; margin-bottom:6px;">
|
||||||
<strong>${escapeHtml(h.titulo || h.tema)}</strong>
|
<strong>${escapeHtml(h.titulo || h.tema)}</strong>
|
||||||
<div style="font-size:0.72rem; color:var(--text-secondary);">${h.faixa_etaria} • ${new Date(h.created_at).toLocaleDateString('pt-BR')}</div>
|
<div style="font-size:0.72rem; color:var(--text-secondary);">${h.faixa_etaria || ''} • ${new Date(h.created_at).toLocaleDateString('pt-BR')}</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
@@ -11433,7 +11473,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
html += `
|
html += `
|
||||||
<div style="background:rgba(239,68,68,0.05); border-left:3px solid #ef4444; padding:8px 12px; border-radius:4px; font-size:0.82rem; margin-bottom:6px;">
|
<div style="background:rgba(239,68,68,0.05); border-left:3px solid #ef4444; padding:8px 12px; border-radius:4px; font-size:0.82rem; margin-bottom:6px;">
|
||||||
<div style="display:flex; justify-content:space-between; font-size:0.75rem; color:#f87171;">
|
<div style="display:flex; justify-content:space-between; font-size:0.75rem; color:#f87171;">
|
||||||
<strong>${escapeHtml(cr.tipo_evento)} (${cr.intensidade})</strong>
|
<strong>${escapeHtml(cr.tipo_evento)} (${escapeHtml(cr.intensidade)})</strong>
|
||||||
<span>${new Date(cr.data_hora).toLocaleString('pt-BR')}</span>
|
<span>${new Date(cr.data_hora).toLocaleString('pt-BR')}</span>
|
||||||
</div>
|
</div>
|
||||||
<p style="margin:4px 0 0 0; color:var(--text-primary);">${escapeHtml(cr.descricao)}</p>
|
<p style="margin:4px 0 0 0; color:var(--text-primary);">${escapeHtml(cr.descricao)}</p>
|
||||||
@@ -11450,16 +11490,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
rels.forEach(r => {
|
rels.forEach(r => {
|
||||||
html += `
|
html += `
|
||||||
<div style="background:rgba(59,130,246,0.05); border-left:3px solid #3b82f6; padding:8px 12px; border-radius:4px; font-size:0.82rem; margin-bottom:6px;">
|
<div style="background:rgba(59,130,246,0.05); border-left:3px solid #3b82f6; padding:8px 12px; border-radius:4px; font-size:0.82rem; margin-bottom:6px;">
|
||||||
<strong>${r.semestre}º Semestre de ${r.ano_letivo} (${r.faixa_etaria})</strong>
|
<strong>${r.semestre}º Semestre de ${r.ano_letivo} (${r.faixa_etaria || ''})</strong>
|
||||||
<p style="margin:4px 0 0 0; color:var(--text-primary); max-height:100px; overflow-y:auto; font-size:0.8rem;">${escapeHtml(r.conteudo_relatorio)}</p>
|
<p style="margin:4px 0 0 0; color:var(--text-primary); max-height:100px; overflow-y:auto; font-size:0.8rem;">${escapeHtml(r.conteudo_relatorio)}</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
timelineContentArea.innerHTML = html;
|
if (timelineContentArea) timelineContentArea.innerHTML = html;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
timelineContentArea.innerHTML = `<p style="color:#ef4444; text-align:center;">Erro: ${err.message}</p>`;
|
if (timelineContentArea) timelineContentArea.innerHTML = `<p style="color:#ef4444; text-align:center; padding:20px;">Erro: ${err.message}</p>`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -11468,7 +11508,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
btnExportFichaConselho.addEventListener('click', async () => {
|
btnExportFichaConselho.addEventListener('click', async () => {
|
||||||
if (!currentTimelineAlunoId) return;
|
if (!currentTimelineAlunoId) return;
|
||||||
try {
|
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();
|
const data = await res.json();
|
||||||
if (!res.ok) throw new Error(data.error || 'Falha ao buscar ficha');
|
if (!res.ok) throw new Error(data.error || 'Falha ao buscar ficha');
|
||||||
|
|
||||||
@@ -11492,16 +11532,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
<button class="btn-p" onclick="window.print()">🖨️ Imprimir Ficha</button>
|
<button class="btn-p" onclick="window.print()">🖨️ Imprimir Ficha</button>
|
||||||
<h1>📋 Ficha Individual de Acompanhamento / Conselho de Classe</h1>
|
<h1>📋 Ficha Individual de Acompanhamento / Conselho de Classe</h1>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div><strong>Aluno(a):</strong> ${aluno.nome}</div>
|
<div><strong>Aluno(a):</strong> ${escapeHtml(aluno.nome)}</div>
|
||||||
<div><strong>Turma:</strong> ${aluno.turma_nome || 'N/A'}</div>
|
<div><strong>Turma:</strong> ${escapeHtml(aluno.turma_nome || 'N/A')}</div>
|
||||||
<div><strong>Data Nasc:</strong> ${aluno.data_nasc ? new Date(aluno.data_nasc).toLocaleDateString('pt-BR') : 'N/A'}</div>
|
<div><strong>Data Nasc:</strong> ${aluno.data_nasc ? new Date(aluno.data_nasc).toLocaleDateString('pt-BR') : 'N/A'}</div>
|
||||||
<div><strong>Educação Especial:</strong> ${aluno.especial ? 'Sim (' + (aluno.especial_detalhes || '') + ')' : 'Não'}</div>
|
<div><strong>Educação Especial:</strong> ${aluno.especial ? 'Sim (' + escapeHtml(aluno.especial_detalhes || '') + ')' : 'Não'}</div>
|
||||||
<div><strong>Total de Observações:</strong> ${data.totalObservacoes}</div>
|
<div><strong>Total de Observações:</strong> ${data.totalObservacoes || 0}</div>
|
||||||
<div><strong>Emissão:</strong> ${data.dataFicha}</div>
|
<div><strong>Emissão:</strong> ${data.dataFicha || new Date().toLocaleDateString('pt-BR')}</div>
|
||||||
</div>
|
</div>
|
||||||
<h3>🌟 Conquistas Pedagógicas:</h3>
|
<h3>🌟 Conquistas Pedagógicas:</h3>
|
||||||
<ul>
|
<ul>
|
||||||
${(data.conquistas || []).map(c => `<li><strong>${c.titulo}</strong> (${c.categoria})</li>`).join('') || '<li>Nenhuma conquista pontual registrada.</li>'}
|
${(data.conquistas || []).map(c => `<li><strong>${escapeHtml(c.titulo)}</strong> (${escapeHtml(c.categoria)})</li>`).join('') || '<li>Nenhuma conquista pontual registrada.</li>'}
|
||||||
</ul>
|
</ul>
|
||||||
<div style="margin-top: 50px; display: flex; justify-content: space-between; border-top: 1px solid #cbd5e1; padding-top: 20px;">
|
<div style="margin-top: 50px; display: flex; justify-content: space-between; border-top: 1px solid #cbd5e1; padding-top: 20px;">
|
||||||
<div style="text-align: center; width: 45%;">___________________________<br>Professora Titular</div>
|
<div style="text-align: center; width: 45%;">___________________________<br>Professora Titular</div>
|
||||||
@@ -11529,12 +11569,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
if (btnCloseCsvImport) btnCloseCsvImport.addEventListener('click', () => csvImportModal.style.display = 'none');
|
if (btnCloseCsvImport) btnCloseCsvImport.addEventListener('click', () => csvImportModal.style.display = 'none');
|
||||||
|
|
||||||
// Botão abrir CSV import (se presente na tela de turmas ou sidebar)
|
window.openCsvImportModal = async () => {
|
||||||
window.openCsvImportModal = () => {
|
if (csvImportModal) csvImportModal.style.display = 'flex';
|
||||||
csvImportModal.style.display = 'flex';
|
|
||||||
if (csvImportTurmaSelect) {
|
if (csvImportTurmaSelect) {
|
||||||
csvImportTurmaSelect.innerHTML = '';
|
csvImportTurmaSelect.innerHTML = '<option value="">Carregando turmas...</option>';
|
||||||
(currentTurmas || []).forEach(t => {
|
const turmas = await window.getGlobalTurmas();
|
||||||
|
csvImportTurmaSelect.innerHTML = '<option value="">-- Selecionar Turma --</option>';
|
||||||
|
turmas.forEach(t => {
|
||||||
const opt = document.createElement('option');
|
const opt = document.createElement('option');
|
||||||
opt.value = t.id;
|
opt.value = t.id;
|
||||||
opt.textContent = t.nome;
|
opt.textContent = t.nome;
|
||||||
@@ -11572,14 +11613,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch('/api/alunos/import-csv', {
|
const res = await fetch('/api/alunos/import-csv', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: getAuthHeaders(),
|
||||||
body: JSON.stringify({ turma_id: turmaId, csv_content: csv })
|
body: JSON.stringify({ turma_id: turmaId, csv_content: csv })
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!res.ok) throw new Error(data.error || 'Erro na importação');
|
if (!res.ok) throw new Error(data.error || 'Erro na importação');
|
||||||
|
|
||||||
alert(`✅ Sucesso! ${data.count} alunos foram importados para a turma.`);
|
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 fetchAlunos === 'function') await fetchAlunos();
|
||||||
if (typeof renderAlunosList === 'function') renderAlunosList();
|
if (typeof renderAlunosList === 'function') renderAlunosList();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -11612,10 +11653,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const btnSendWhatsappDirect = document.getElementById('btnSendWhatsappDirect');
|
const btnSendWhatsappDirect = document.getElementById('btnSendWhatsappDirect');
|
||||||
const criseHistoryList = document.getElementById('criseHistoryList');
|
const criseHistoryList = document.getElementById('criseHistoryList');
|
||||||
|
|
||||||
function populateCriseTurmas() {
|
async function populateCriseTurmas() {
|
||||||
if (!criseTurmaSelect) return;
|
if (!criseTurmaSelect) return;
|
||||||
|
criseTurmaSelect.innerHTML = '<option value="">-- Carregando Turmas... --</option>';
|
||||||
|
const turmas = await window.getGlobalTurmas();
|
||||||
criseTurmaSelect.innerHTML = '<option value="">-- Selecionar Turma --</option>';
|
criseTurmaSelect.innerHTML = '<option value="">-- Selecionar Turma --</option>';
|
||||||
(currentTurmas || []).forEach(t => {
|
turmas.forEach(t => {
|
||||||
const opt = document.createElement('option');
|
const opt = document.createElement('option');
|
||||||
opt.value = t.id;
|
opt.value = t.id;
|
||||||
opt.textContent = t.nome;
|
opt.textContent = t.nome;
|
||||||
@@ -11624,50 +11667,66 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (btnProtocoloCrise) {
|
if (btnProtocoloCrise) {
|
||||||
btnProtocoloCrise.addEventListener('click', () => {
|
btnProtocoloCrise.addEventListener('click', async (e) => {
|
||||||
criseModal.style.display = 'flex';
|
e.preventDefault();
|
||||||
populateCriseTurmas();
|
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) {
|
if (btnOpenCrisesHistory) {
|
||||||
btnOpenCrisesHistory.addEventListener('click', async () => {
|
btnOpenCrisesHistory.addEventListener('click', async () => {
|
||||||
criseHistoryModal.style.display = 'flex';
|
if (criseHistoryModal) criseHistoryModal.style.display = 'flex';
|
||||||
if (!criseHistoryList) return;
|
if (!criseHistoryList) return;
|
||||||
criseHistoryList.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Carregando...</p>';
|
criseHistoryList.innerHTML = '<p style="text-align:center; color:var(--text-secondary); padding:20px;">Carregando histórico...</p>';
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/crises/list');
|
const res = await fetch('/api/crises/list', { headers: getAuthHeaders() });
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
if (!res.ok) throw new Error(data.error || 'Erro ao carregar');
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
criseHistoryList.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Nenhuma ocorrência registrada.</p>';
|
criseHistoryList.innerHTML = '<p style="text-align:center; color:var(--text-secondary); padding:20px;">Nenhuma ocorrência registrada ainda.</p>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
criseHistoryList.innerHTML = data.map(c => `
|
criseHistoryList.innerHTML = data.map(c => `
|
||||||
<div style="background:rgba(255,255,255,0.02); border:1px solid var(--border-light); padding:12px; border-radius:8px; display:flex; flex-direction:column; gap:4px; position:relative;">
|
<div style="background:rgba(255,255,255,0.02); border:1px solid var(--border-light); padding:12px; border-radius:8px; display:flex; flex-direction:column; gap:4px; position:relative;">
|
||||||
<div style="display:flex; justify-content:space-between; padding-right:24px;">
|
<div style="display:flex; justify-content:space-between; padding-right:24px;">
|
||||||
<strong style="color:#ef4444; font-size:0.9rem;">${escapeHtml(c.aluno_nome)} • ${escapeHtml(c.tipo_evento)}</strong>
|
<strong style="color:#ef4444; font-size:0.9rem;">${escapeHtml(c.aluno_nome)} • ${escapeHtml(c.tipo_evento)} (${escapeHtml(c.intensidade || 'Moderada')})</strong>
|
||||||
<span style="font-size:0.72rem; color:var(--text-secondary);">${new Date(c.data_hora).toLocaleString('pt-BR')}</span>
|
<span style="font-size:0.72rem; color:var(--text-secondary);">${new Date(c.data_hora).toLocaleString('pt-BR')}</span>
|
||||||
</div>
|
</div>
|
||||||
<p style="margin:4px 0; font-size:0.82rem; color:var(--text-primary);">${escapeHtml(c.descricao)}</p>
|
<p style="margin:4px 0; font-size:0.82rem; color:var(--text-primary);">${escapeHtml(c.descricao)}</p>
|
||||||
<div style="font-size:0.75rem; color:var(--text-secondary);"><strong>Medidas:</strong> ${escapeHtml(c.medidas_tomadas)}</div>
|
<div style="font-size:0.75rem; color:var(--text-secondary);"><strong>Medidas adotadas:</strong> ${escapeHtml(c.medidas_tomadas)}</div>
|
||||||
<button onclick="deleteCriseRecord('${c.id}')" style="position:absolute; top:8px; right:8px; background:none; border:none; color:#ef4444; cursor:pointer;" title="Excluir">🗑️</button>
|
<button onclick="deleteCriseRecord('${c.id}')" style="position:absolute; top:8px; right:8px; background:none; border:none; color:#ef4444; cursor:pointer;" title="Excluir">🗑️</button>
|
||||||
</div>
|
</div>
|
||||||
`).join('');
|
`).join('');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
criseHistoryList.innerHTML = `<p style="color:#ef4444;">Erro ao carregar: ${e.message}</p>`;
|
criseHistoryList.innerHTML = `<p style="color:#ef4444; text-align:center;">Erro: ${e.message}</p>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.deleteCriseRecord = async (id) => {
|
window.deleteCriseRecord = async (id) => {
|
||||||
if (confirm('Deseja excluir este registro de mediação?')) {
|
if (confirm('Deseja realmente excluir este registro de ocorrência?')) {
|
||||||
await fetch(`/api/crises/${id}`, { method: 'DELETE' });
|
try {
|
||||||
if (btnOpenCrisesHistory) btnOpenCrisesHistory.click();
|
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) {
|
if (btnSalvarCrise) {
|
||||||
btnSalvarCrise.addEventListener('click', async () => {
|
btnSalvarCrise.addEventListener('click', async () => {
|
||||||
@@ -11689,7 +11748,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch('/api/crises/register', {
|
const res = await fetch('/api/crises/register', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: getAuthHeaders(),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
aluno_nome: alunoNome,
|
aluno_nome: alunoNome,
|
||||||
turma_id: turmaId,
|
turma_id: turmaId,
|
||||||
@@ -11708,7 +11767,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
btnSendWhatsappDirect.href = `https://api.whatsapp.com/send?text=${encodeURIComponent(data.mensagemWhatsapp || '')}`;
|
btnSendWhatsappDirect.href = `https://api.whatsapp.com/send?text=${encodeURIComponent(data.mensagemWhatsapp || '')}`;
|
||||||
btnSendWhatsappDirect.style.display = 'block';
|
btnSendWhatsappDirect.style.display = 'block';
|
||||||
}
|
}
|
||||||
alert('✅ Protocolo registrado com sucesso! Mensagem para os pais gerada.');
|
showToast('✅ Ocorrência registrada e mensagem gerada!', 'success');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('Erro ao registrar crise: ' + err.message);
|
alert('Erro ao registrar crise: ' + err.message);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -11722,7 +11781,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
btnCopyCriseWhatsapp.addEventListener('click', () => {
|
btnCopyCriseWhatsapp.addEventListener('click', () => {
|
||||||
if (criseWhatsappOutput && criseWhatsappOutput.textContent) {
|
if (criseWhatsappOutput && criseWhatsappOutput.textContent) {
|
||||||
navigator.clipboard.writeText(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 btnPrintAtaPdf = document.getElementById('btnPrintAtaPdf');
|
||||||
const atasHistoryList = document.getElementById('atasHistoryList');
|
const atasHistoryList = document.getElementById('atasHistoryList');
|
||||||
|
|
||||||
function populateAtaTurmas() {
|
async function populateAtaTurmas() {
|
||||||
if (!ataTurmaSelect) return;
|
if (!ataTurmaSelect) return;
|
||||||
|
ataTurmaSelect.innerHTML = '<option value="">-- Carregando Turmas... --</option>';
|
||||||
|
const turmas = await window.getGlobalTurmas();
|
||||||
ataTurmaSelect.innerHTML = '<option value="">-- Geral / Toda a Escola --</option>';
|
ataTurmaSelect.innerHTML = '<option value="">-- Geral / Toda a Escola --</option>';
|
||||||
(currentTurmas || []).forEach(t => {
|
turmas.forEach(t => {
|
||||||
const opt = document.createElement('option');
|
const opt = document.createElement('option');
|
||||||
opt.value = t.id;
|
opt.value = t.id;
|
||||||
opt.textContent = t.nome;
|
opt.textContent = t.nome;
|
||||||
@@ -11761,12 +11822,19 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (btnAtasReuniao) {
|
if (btnAtasReuniao) {
|
||||||
btnAtasReuniao.addEventListener('click', () => {
|
btnAtasReuniao.addEventListener('click', async (e) => {
|
||||||
ataModal.style.display = 'flex';
|
e.preventDefault();
|
||||||
populateAtaTurmas();
|
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) {
|
if (btnGerarAta) {
|
||||||
btnGerarAta.addEventListener('click', async () => {
|
btnGerarAta.addEventListener('click', async () => {
|
||||||
@@ -11789,7 +11857,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
try {
|
try {
|
||||||
const res = await fetch('/api/atas/generate', {
|
const res = await fetch('/api/atas/generate', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: getAuthHeaders(),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
tipo_reuniao: tipo,
|
tipo_reuniao: tipo,
|
||||||
titulo: titulo,
|
titulo: titulo,
|
||||||
@@ -11805,7 +11873,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
if (!res.ok) throw new Error(data.error || 'Falha ao redigir ata');
|
if (!res.ok) throw new Error(data.error || 'Falha ao redigir ata');
|
||||||
|
|
||||||
if (ataOutputText) ataOutputText.textContent = data.textoAta || '';
|
if (ataOutputText) ataOutputText.textContent = data.textoAta || '';
|
||||||
alert('✅ Ata formal redigida com sucesso!');
|
showToast('✅ Ata formal gerada com sucesso!', 'success');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('Erro ao gerar ata: ' + err.message);
|
alert('Erro ao gerar ata: ' + err.message);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -11819,7 +11887,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
btnCopyAta.addEventListener('click', () => {
|
btnCopyAta.addEventListener('click', () => {
|
||||||
if (ataOutputText && ataOutputText.textContent) {
|
if (ataOutputText && ataOutputText.textContent) {
|
||||||
navigator.clipboard.writeText(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) {
|
if (btnOpenAtasHistory) {
|
||||||
btnOpenAtasHistory.addEventListener('click', async () => {
|
btnOpenAtasHistory.addEventListener('click', async () => {
|
||||||
atasHistoryModal.style.display = 'flex';
|
if (atasHistoryModal) atasHistoryModal.style.display = 'flex';
|
||||||
if (!atasHistoryList) return;
|
if (!atasHistoryList) return;
|
||||||
atasHistoryList.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Carregando atas...</p>';
|
atasHistoryList.innerHTML = '<p style="text-align:center; color:var(--text-secondary); padding:20px;">Carregando atas...</p>';
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/atas/list');
|
const res = await fetch('/api/atas/list', { headers: getAuthHeaders() });
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
if (!res.ok) throw new Error(data.error || 'Erro ao carregar histórico');
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
atasHistoryList.innerHTML = '<p style="text-align:center; color:var(--text-secondary);">Nenhuma ata salva.</p>';
|
atasHistoryList.innerHTML = '<p style="text-align:center; color:var(--text-secondary); padding:20px;">Nenhuma ata salva ainda.</p>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
atasHistoryList.innerHTML = data.map(a => `
|
atasHistoryList.innerHTML = data.map(a => `
|
||||||
@@ -11874,19 +11943,27 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
</div>
|
</div>
|
||||||
`).join('');
|
`).join('');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
atasHistoryList.innerHTML = `<p style="color:#ef4444;">Erro: ${e.message}</p>`;
|
atasHistoryList.innerHTML = `<p style="color:#ef4444; text-align:center;">Erro: ${e.message}</p>`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.deleteAtaRecord = async (id) => {
|
window.deleteAtaRecord = async (id) => {
|
||||||
if (confirm('Deseja excluir esta ata?')) {
|
if (confirm('Deseja realmente excluir esta ata?')) {
|
||||||
await fetch(`/api/atas/${id}`, { method: 'DELETE' });
|
try {
|
||||||
if (btnOpenAtasHistory) btnOpenAtasHistory.click();
|
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
|
// 5. STICKERS GAMIFICADOS & CARTELA A4 DE IMPRESSÃO
|
||||||
@@ -11903,10 +11980,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
const stickersListGrid = document.getElementById('stickersListGrid');
|
const stickersListGrid = document.getElementById('stickersListGrid');
|
||||||
const btnPrintStickerSheet = document.getElementById('btnPrintStickerSheet');
|
const btnPrintStickerSheet = document.getElementById('btnPrintStickerSheet');
|
||||||
|
|
||||||
function populateStickerTurmas() {
|
async function populateStickerTurmas() {
|
||||||
if (!stickerTurmaSelect) return;
|
if (!stickerTurmaSelect) return;
|
||||||
|
stickerTurmaSelect.innerHTML = '<option value="">-- Carregando Turmas... --</option>';
|
||||||
|
const turmas = await window.getGlobalTurmas();
|
||||||
stickerTurmaSelect.innerHTML = '<option value="">-- Selecionar Turma --</option>';
|
stickerTurmaSelect.innerHTML = '<option value="">-- Selecionar Turma --</option>';
|
||||||
(currentTurmas || []).forEach(t => {
|
turmas.forEach(t => {
|
||||||
const opt = document.createElement('option');
|
const opt = document.createElement('option');
|
||||||
opt.value = t.id;
|
opt.value = t.id;
|
||||||
opt.textContent = t.nome;
|
opt.textContent = t.nome;
|
||||||
@@ -11916,41 +11995,54 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
async function loadStickersGrid() {
|
async function loadStickersGrid() {
|
||||||
if (!stickersListGrid) return;
|
if (!stickersListGrid) return;
|
||||||
stickersListGrid.innerHTML = '<p style="text-align:center; color:var(--text-secondary); grid-column:1/-1;">Carregando...</p>';
|
stickersListGrid.innerHTML = '<p style="text-align:center; color:var(--text-secondary); grid-column:1/-1; padding:20px;">Carregando conquistas...</p>';
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/stickers/list');
|
const res = await fetch('/api/stickers/list', { headers: getAuthHeaders() });
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
|
if (!res.ok) throw new Error(data.error || 'Erro ao buscar');
|
||||||
if (data.length === 0) {
|
if (data.length === 0) {
|
||||||
stickersListGrid.innerHTML = '<p style="text-align:center; color:var(--text-secondary); grid-column:1/-1;">Nenhum sticker emitido ainda.</p>';
|
stickersListGrid.innerHTML = '<p style="text-align:center; color:var(--text-secondary); grid-column:1/-1; padding:20px;">Nenhum sticker emitido ainda.</p>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
stickersListGrid.innerHTML = data.map(s => `
|
stickersListGrid.innerHTML = data.map(s => `
|
||||||
<div style="background:rgba(255,255,255,0.03); border:2px dashed rgba(245,158,11,0.4); border-radius:10px; padding:10px; text-align:center; display:flex; flex-direction:column; align-items:center; gap:4px; position:relative;">
|
<div style="background:rgba(255,255,255,0.03); border:2px dashed rgba(245,158,11,0.4); border-radius:10px; padding:10px; text-align:center; display:flex; flex-direction:column; align-items:center; gap:4px; position:relative;">
|
||||||
<span style="font-size:1.8rem;">${s.icone || '🌟'}</span>
|
<span style="font-size:1.8rem;">${s.icone || '🌟'}</span>
|
||||||
<strong style="font-size:0.8rem; color:#fbbf24;">${escapeHtml(s.titulo)}</strong>
|
<strong style="font-size:0.82rem; color:#fbbf24;">${escapeHtml(s.titulo)}</strong>
|
||||||
<span style="font-size:0.75rem; color:var(--text-primary);">${escapeHtml(s.aluno_nome)}</span>
|
<span style="font-size:0.75rem; color:var(--text-primary); font-weight:600;">${escapeHtml(s.aluno_nome)}</span>
|
||||||
${s.qr_code_url ? `<img src="${s.qr_code_url}" style="width:50px; height:50px; margin-top:4px; border-radius:4px;" title="QR Code para a família">` : ''}
|
<span style="font-size:0.68rem; color:var(--text-secondary);">${escapeHtml(s.categoria || '')}</span>
|
||||||
|
${s.qr_code_url ? `<img src="${s.qr_code_url}" style="width:55px; height:55px; margin-top:4px; border-radius:4px; background:white; padding:2px;" title="QR Code para a família">` : ''}
|
||||||
<button onclick="deleteStickerRecord('${s.id}')" style="position:absolute; top:4px; right:4px; background:none; border:none; color:#ef4444; font-size:0.8rem; cursor:pointer;" title="Excluir">✕</button>
|
<button onclick="deleteStickerRecord('${s.id}')" style="position:absolute; top:4px; right:4px; background:none; border:none; color:#ef4444; font-size:0.8rem; cursor:pointer;" title="Excluir">✕</button>
|
||||||
</div>
|
</div>
|
||||||
`).join('');
|
`).join('');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
stickersListGrid.innerHTML = `<p style="color:#ef4444; grid-column:1/-1;">Erro: ${e.message}</p>`;
|
stickersListGrid.innerHTML = `<p style="color:#ef4444; grid-column:1/-1; text-align:center;">Erro: ${e.message}</p>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (btnStickersConquistas) {
|
if (btnStickersConquistas) {
|
||||||
btnStickersConquistas.addEventListener('click', () => {
|
btnStickersConquistas.addEventListener('click', async (e) => {
|
||||||
stickerModal.style.display = 'flex';
|
e.preventDefault();
|
||||||
populateStickerTurmas();
|
e.stopPropagation();
|
||||||
loadStickersGrid();
|
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) => {
|
window.deleteStickerRecord = async (id) => {
|
||||||
if (confirm('Deseja excluir este sticker?')) {
|
if (confirm('Deseja realmente excluir este sticker?')) {
|
||||||
await fetch(`/api/stickers/${id}`, { method: 'DELETE' });
|
try {
|
||||||
loadStickersGrid();
|
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;
|
const turmaId = stickerTurmaSelect ? stickerTurmaSelect.value : null;
|
||||||
|
|
||||||
if (!alunoNome || !titulo || !desc) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11976,9 +12068,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
else if (cat.includes('Roda')) icone = '🗣️';
|
else if (cat.includes('Roda')) icone = '🗣️';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
btnEmitirSticker.disabled = true;
|
||||||
|
btnEmitirSticker.textContent = '⏳ Emitindo...';
|
||||||
|
|
||||||
const res = await fetch('/api/stickers/create', {
|
const res = await fetch('/api/stickers/create', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: getAuthHeaders(),
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
aluno_nome: alunoNome,
|
aluno_nome: alunoNome,
|
||||||
turma_id: turmaId,
|
turma_id: turmaId,
|
||||||
@@ -11990,10 +12085,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
if (!res.ok) throw new Error(data.error || 'Falha ao emitir sticker');
|
if (!res.ok) throw new Error(data.error || 'Falha ao emitir sticker');
|
||||||
alert('✅ Conquista registrada com sucesso!');
|
showToast('✅ Conquista emitida com sucesso!', 'success');
|
||||||
loadStickersGrid();
|
if (stickerAlunoInput) stickerAlunoInput.value = '';
|
||||||
|
if (stickerTituloInput) stickerTituloInput.value = '';
|
||||||
|
if (stickerDescricaoInput) stickerDescricaoInput.value = '';
|
||||||
|
await loadStickersGrid();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert('Erro: ' + err.message);
|
alert('Erro: ' + err.message);
|
||||||
|
} finally {
|
||||||
|
btnEmitirSticker.disabled = false;
|
||||||
|
btnEmitirSticker.textContent = '🏅 Emitir Conquista';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -12002,9 +12103,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
if (btnPrintStickerSheet) {
|
if (btnPrintStickerSheet) {
|
||||||
btnPrintStickerSheet.addEventListener('click', async () => {
|
btnPrintStickerSheet.addEventListener('click', async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch('/api/stickers/list');
|
const res = await fetch('/api/stickers/list', { headers: getAuthHeaders() });
|
||||||
const stickers = await res.json();
|
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.');
|
alert('Emita ao menos um sticker antes de imprimir a cartela.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -12018,7 +12119,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
<strong style="font-size: 0.95rem; color: #b45309; margin-top: 4px;">${escapeHtml(s.titulo)}</strong>
|
<strong style="font-size: 0.95rem; color: #b45309; margin-top: 4px;">${escapeHtml(s.titulo)}</strong>
|
||||||
<div style="font-size: 0.85rem; font-weight: bold; color: #1e293b;">${escapeHtml(s.aluno_nome)}</div>
|
<div style="font-size: 0.85rem; font-weight: bold; color: #1e293b;">${escapeHtml(s.aluno_nome)}</div>
|
||||||
<p style="font-size: 0.72rem; color: #64748b; margin: 4px 0 6px 0;">${escapeHtml(s.descricao)}</p>
|
<p style="font-size: 0.72rem; color: #64748b; margin: 4px 0 6px 0;">${escapeHtml(s.descricao)}</p>
|
||||||
${s.qr_code_url ? `<img src="${s.qr_code_url}" style="width: 60px; height: 60px; border-radius: 4px; border: 1px solid #e2e8f0;">` : ''}
|
${s.qr_code_url ? `<img src="${s.qr_code_url}" style="width: 60px; height: 60px; border-radius: 4px; border: 1px solid #e2e8f0; background: white; padding: 2px;">` : ''}
|
||||||
<div style="font-size: 0.65rem; color: #94a3b8; margin-top: 4px;">Pedagog • Conquista Escolar</div>
|
<div style="font-size: 0.65rem; color: #94a3b8; margin-top: 4px;">Pedagog • Conquista Escolar</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user