const fs = require('fs'); const path = require('path'); const appFile = path.join(__dirname, 'public', 'app.js'); let appCode = fs.readFileSync(appFile, 'utf8'); const startIndex = appCode.indexOf('// ============================================================\n // MODAL: MINHA TURMA'); const endIndex = appCode.indexOf('// ============================================================\n // CRUD DE MODELOS DE RELATÓRIO'); if (startIndex === -1 || endIndex === -1) { console.error("Could not find start or end index for replacement"); process.exit(1); } const newLogic = `// ============================================================ // MODAL: MINHA TURMA (COM MÚLTIPLAS TURMAS E SUPABASE) // ============================================================ const minhaTurmaModal = document.getElementById('minhaTurmaModal'); const btnMinhaTurma = document.getElementById('btnMinhaTurma'); const btnCloseMinhaTurmaModal = document.getElementById('btnCloseMinhaTurmaModal'); // Turmas List & Form const turmasList = document.getElementById('turmasList'); const btnCreateTurma = document.getElementById('btnCreateTurma'); const btnCancelTurma = document.getElementById('btnCancelTurma'); const btnSaveTurmaConfig = document.getElementById('btnSaveTurmaConfig'); const configTurmaId = document.getElementById('configTurmaId'); const configTurmaNome = document.getElementById('configTurmaNome'); const configTurmaSala = document.getElementById('configTurmaSala'); const configTurmaPeriodo = document.getElementById('configTurmaPeriodo'); const configTurmaProfTitular = document.getElementById('configTurmaProfTitular'); const configTurmaProfAux1 = document.getElementById('configTurmaProfAux1'); const configTurmaProfAux2 = document.getElementById('configTurmaProfAux2'); const configTurmaCuidadora = document.getElementById('configTurmaCuidadora'); const turmaFormTitle = document.getElementById('turmaFormTitle'); // Alunos List & Form const filterAlunosTurma = document.getElementById('filterAlunosTurma'); const childrenList = document.getElementById('childrenList'); const btnCreateChild = document.getElementById('btnCreateChild'); const btnCancelChild = document.getElementById('btnCancelChild'); const btnSaveChild = document.getElementById('btnSaveChild'); const childFormTitle = document.getElementById('childFormTitle'); const cFormId = document.getElementById('childFormId'); const cFormTurma = document.getElementById('childFormTurma'); const cFormNome = document.getElementById('childFormNome'); const cFormApelido = document.getElementById('childFormApelido'); const cFormDataNasc = document.getElementById('childFormDataNasc'); const cFormEspecial = document.getElementById('childFormEspecial'); const divEspecialDetalhes = document.getElementById('divEspecialDetalhes'); const cFormEspecialDetalhes = document.getElementById('childFormEspecialDetalhes'); const cFormPais = document.getElementById('childFormPais'); const cFormAutorizados = document.getElementById('childFormAutorizados'); // Tabs const tabTurmaConfig = document.getElementById('tabTurmaConfig'); const tabTurmaAlunos = document.getElementById('tabTurmaAlunos'); const turmaConfigSection = document.getElementById('turmaConfigSection'); const turmaAlunosSection = document.getElementById('turmaAlunosSection'); let currentTurmas = []; let currentAlunos = []; // API Calls const fetchTurmas = async () => { try { const res = await fetch('/api/turmas'); currentTurmas = await res.json(); populateTurmaSelects(); return currentTurmas; } catch(e) { console.error(e); return []; } }; const fetchAlunos = async () => { try { const res = await fetch('/api/alunos'); currentAlunos = await res.json(); localStorage.setItem('camila_turma', JSON.stringify(currentAlunos)); return currentAlunos; } catch(e) { console.error(e); return []; } }; const populateTurmaSelects = () => { const opts = '' + currentTurmas.map(t => \`\`).join(''); if(filterAlunosTurma) filterAlunosTurma.innerHTML = opts; const formOpts = '' + currentTurmas.map(t => \`\`).join(''); if(cFormTurma) cFormTurma.innerHTML = formOpts; if(document.getElementById('emitirFilterTurma')) { document.getElementById('emitirFilterTurma').innerHTML = '' + currentTurmas.map(t => \`\`).join(''); } }; // Tabs Logic if (tabTurmaConfig) { tabTurmaConfig.addEventListener('click', () => { tabTurmaConfig.classList.add('active'); tabTurmaConfig.style.borderBottomColor = 'var(--brand-green)'; tabTurmaConfig.style.color = 'var(--brand-green)'; tabTurmaAlunos.classList.remove('active'); tabTurmaAlunos.style.borderBottomColor = 'transparent'; tabTurmaAlunos.style.color = 'var(--text-secondary)'; turmaConfigSection.style.display = 'flex'; turmaAlunosSection.style.display = 'none'; }); } if (tabTurmaAlunos) { tabTurmaAlunos.addEventListener('click', () => { tabTurmaAlunos.classList.add('active'); tabTurmaAlunos.style.borderBottomColor = 'var(--brand-green)'; tabTurmaAlunos.style.color = 'var(--brand-green)'; tabTurmaConfig.classList.remove('active'); tabTurmaConfig.style.borderBottomColor = 'transparent'; tabTurmaConfig.style.color = 'var(--text-secondary)'; turmaAlunosSection.style.display = 'flex'; turmaConfigSection.style.display = 'none'; }); } // Turmas Logic const clearTurmaForm = () => { configTurmaId.value = ''; configTurmaNome.value = ''; configTurmaSala.value = ''; configTurmaPeriodo.value = 'Integral'; configTurmaProfTitular.value = ''; configTurmaProfAux1.value = ''; configTurmaProfAux2.value = ''; configTurmaCuidadora.value = ''; turmaFormTitle.textContent = 'Cadastrar Turma'; }; const renderTurmasList = () => { if(!turmasList) return; if(currentTurmas.length === 0) { turmasList.innerHTML = '
Nenhuma turma cadastrada.
'; return; } turmasList.innerHTML = currentTurmas.map(t => \`
\${escapeHtml(t.nome)}
\${t.periodo || ''} \${t.sala ? '- ' + t.sala : ''}
\`).join(''); }; window.editTurma = (id) => { const t = currentTurmas.find(x => x.id === id); if(!t) return; configTurmaId.value = t.id; configTurmaNome.value = t.nome || ''; configTurmaSala.value = t.sala || ''; configTurmaPeriodo.value = t.periodo || 'Integral'; configTurmaProfTitular.value = t.prof_titular || ''; configTurmaProfAux1.value = t.prof_aux1 || ''; configTurmaProfAux2.value = t.prof_aux2 || ''; configTurmaCuidadora.value = t.cuidadora || ''; turmaFormTitle.textContent = 'Editar Turma'; }; window.deleteTurma = async (id) => { const isOk = await showCustomConfirm('Excluir Turma', 'Deseja excluir esta turma? Todos os alunos associados a ela também serão excluídos.', true); if(isOk) { await fetch('/api/turmas/' + id, { method: 'DELETE' }); await fetchTurmas(); await fetchAlunos(); renderTurmasList(); renderAlunosList(); clearTurmaForm(); } }; if(btnCreateTurma) btnCreateTurma.addEventListener('click', clearTurmaForm); if(btnCancelTurma) btnCancelTurma.addEventListener('click', clearTurmaForm); if (btnSaveTurmaConfig) { btnSaveTurmaConfig.addEventListener('click', async () => { const nome = configTurmaNome.value.trim(); if(!nome) { showCustomAlert('Aviso', 'O Nome da Turma é obrigatório.'); return; } const body = { nome, sala: configTurmaSala.value, periodo: configTurmaPeriodo.value, profTitular: configTurmaProfTitular.value, profAux1: configTurmaProfAux1.value, profAux2: configTurmaProfAux2.value, cuidadora: configTurmaCuidadora.value }; const id = configTurmaId.value; const url = id ? '/api/turmas/' + id : '/api/turmas'; const method = id ? 'PUT' : 'POST'; try { const res = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); if(res.ok) { showCustomAlert('Sucesso', 'Turma salva com sucesso!'); await fetchTurmas(); renderTurmasList(); clearTurmaForm(); } else { showCustomAlert('Erro', 'Falha ao salvar turma.'); } } catch(e) { console.error(e); } }); } // Alunos Logic const clearChildForm = () => { cFormId.value = ''; cFormTurma.value = filterAlunosTurma ? filterAlunosTurma.value : ''; cFormNome.value = ''; cFormApelido.value = ''; cFormDataNasc.value = ''; cFormEspecial.checked = false; cFormEspecialDetalhes.value = ''; divEspecialDetalhes.style.display = 'none'; cFormPais.value = ''; cFormAutorizados.value = ''; childFormTitle.textContent = 'Cadastrar Criança'; }; if (cFormEspecial) { cFormEspecial.addEventListener('change', () => { divEspecialDetalhes.style.display = cFormEspecial.checked ? 'flex' : 'none'; }); } const renderAlunosList = () => { if (!childrenList) return; const filterTurmaId = filterAlunosTurma ? filterAlunosTurma.value : ''; let filtered = currentAlunos; if(filterTurmaId) { filtered = currentAlunos.filter(a => a.turma_id === filterTurmaId); } if (filtered.length === 0) { childrenList.innerHTML = '
Nenhuma criança encontrada.
'; return; } filtered.sort((a, b) => (a.nome || '').localeCompare(b.nome || '')); childrenList.innerHTML = filtered.map(c => { const turmaObj = currentTurmas.find(t => t.id === c.turma_id); const turmaNome = turmaObj ? turmaObj.nome : 'Sem turma'; return \`
\${escapeHtml(c.nome)} \${c.especial ? '⭐' : ''}
\${escapeHtml(turmaNome)} \${c.apelido ? '- ' + escapeHtml(c.apelido) : ''}
\`}).join(''); }; if(filterAlunosTurma) { filterAlunosTurma.addEventListener('change', () => { renderAlunosList(); if(cFormTurma) cFormTurma.value = filterAlunosTurma.value; }); } window.editChild = (id) => { const c = currentAlunos.find(x => x.id === id); if (!c) return; cFormId.value = c.id; cFormTurma.value = c.turma_id || ''; cFormNome.value = c.nome || ''; cFormApelido.value = c.apelido || ''; if(c.data_nasc) { cFormDataNasc.value = c.data_nasc.split('T')[0]; } else { cFormDataNasc.value = ''; } cFormEspecial.checked = !!c.especial; cFormEspecialDetalhes.value = c.especial_detalhes || ''; divEspecialDetalhes.style.display = c.especial ? 'flex' : 'none'; cFormPais.value = c.pais || ''; cFormAutorizados.value = c.autorizados || ''; childFormTitle.textContent = 'Editar Criança'; }; window.deleteChild = async (id) => { const isOk = await showCustomConfirm('Excluir', 'Deseja excluir esta criança? Isso não removerá as observações já feitas.', true); if (isOk) { await fetch('/api/alunos/' + id, { method: 'DELETE' }); await fetchAlunos(); renderAlunosList(); clearChildForm(); } }; if (btnMinhaTurma) { btnMinhaTurma.addEventListener('click', async () => { minhaTurmaModal.style.display = 'flex'; await fetchTurmas(); await fetchAlunos(); renderTurmasList(); renderAlunosList(); clearTurmaForm(); clearChildForm(); }); } if (btnCloseMinhaTurmaModal) btnCloseMinhaTurmaModal.addEventListener('click', () => minhaTurmaModal.style.display = 'none'); if (minhaTurmaModal) { minhaTurmaModal.addEventListener('click', (e) => { if (e.target === minhaTurmaModal) minhaTurmaModal.style.display = 'none'; }); } if (btnCreateChild) btnCreateChild.addEventListener('click', clearChildForm); if (btnCancelChild) btnCancelChild.addEventListener('click', clearChildForm); if (btnSaveChild) { btnSaveChild.addEventListener('click', async () => { if (!cFormNome.value.trim() || !cFormTurma.value) { showCustomAlert('Aviso', 'O Nome da Criança e a Turma são obrigatórios.'); return; } const id = cFormId.value; const body = { turma_id: cFormTurma.value, nome: cFormNome.value.trim(), apelido: cFormApelido.value.trim(), data_nasc: cFormDataNasc.value || null, especial: cFormEspecial.checked, especial_detalhes: cFormEspecialDetalhes.value.trim(), pais: cFormPais.value.trim(), autorizados: cFormAutorizados.value.trim() }; const url = id ? '/api/alunos/' + id : '/api/alunos'; const method = id ? 'PUT' : 'POST'; try { const res = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); if(res.ok) { await fetchAlunos(); renderAlunosList(); clearChildForm(); showCustomAlert('Sucesso', 'Criança salva com sucesso!'); } else { showCustomAlert('Erro', 'Falha ao salvar criança.'); } } catch(e) { console.error(e); } }); } // Preencher com Voz const btnVoiceRecordChild = document.getElementById('btnVoiceRecordChild'); if (btnVoiceRecordChild && (window.SpeechRecognition || window.webkitSpeechRecognition)) { const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; const formRecognition = new SpeechRecognition(); formRecognition.lang = 'pt-BR'; formRecognition.continuous = false; formRecognition.interimResults = false; formRecognition.onstart = () => { btnVoiceRecordChild.innerHTML = '🛑 Gravando... (Clique para parar)'; btnVoiceRecordChild.style.background = 'rgba(239, 68, 68, 0.1)'; btnVoiceRecordChild.style.color = '#ef4444'; btnVoiceRecordChild.style.borderColor = '#ef4444'; }; formRecognition.onresult = async (event) => { const transcript = event.results[0][0].transcript; btnVoiceRecordChild.innerHTML = '⏳ Processando com IA...'; try { const response = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ messages: [{ role: 'user', content: \`A professora ditou as seguintes informações para cadastrar uma criança na turma: "\${transcript}". Por favor, extraia os dados e retorne APENAS um JSON válido com os seguintes campos: "nome", "apelido", "data_nasc" (formato YYYY-MM-DD), "especial" (boolean), "especial_detalhes", "pais", "autorizados". Se algum dado não for mencionado, deixe a string vazia ou false para boolean.\` }], temperature: 0.1 }) }); if (response.ok) { const data = await response.json(); const assistantReply = data.message; const match = assistantReply.match(/\`\`\`json\\n([\\s\\S]*?)\\n\`\`\`/) || assistantReply.match(/\\{[\\s\\S]*\\}/); if (match) { const parsed = JSON.parse(match[1] || match[0]); if (parsed.nome) cFormNome.value = parsed.nome; if (parsed.apelido) cFormApelido.value = parsed.apelido; if (parsed.data_nasc) cFormDataNasc.value = parsed.data_nasc; if (parsed.especial) cFormEspecial.checked = parsed.especial; divEspecialDetalhes.style.display = cFormEspecial.checked ? 'flex' : 'none'; if (parsed.especial_detalhes) cFormEspecialDetalhes.value = parsed.especial_detalhes; if (parsed.pais) cFormPais.value = parsed.pais; if (parsed.autorizados) cFormAutorizados.value = parsed.autorizados; } } } catch (err) { console.error('Erro ao processar voz:', err); showCustomAlert('Erro', 'Não foi possível extrair os dados. Tente novamente ou preencha manualmente.'); } }; formRecognition.onend = () => { btnVoiceRecordChild.innerHTML = '🎤 Preencher com Voz'; btnVoiceRecordChild.style.background = 'rgba(16, 163, 127, 0.1)'; btnVoiceRecordChild.style.color = 'var(--brand-green)'; btnVoiceRecordChild.style.borderColor = 'var(--brand-green)'; }; btnVoiceRecordChild.addEventListener('click', () => { if (btnVoiceRecordChild.innerHTML.includes('Gravando')) { formRecognition.stop(); } else { formRecognition.start(); } }); } // Mostra detalhe da observação em modal const showObsDetail = (mdText) => { const modal = document.createElement('div'); modal.className = 'settings-modal'; modal.style.display = 'flex'; modal.innerHTML = \`

📋 Observação

\${marked.parse(mdText.replace(/^---[\\s\\S]*?---\\n/, ''))}
\`; document.body.appendChild(modal); modal.addEventListener('click', (e) => { if (e.target === modal) modal.remove(); }); }; // `; appCode = appCode.slice(0, startIndex) + newLogic + appCode.slice(endIndex); fs.writeFileSync(appFile, appCode);