diff --git a/patch_app_js.js b/patch_app_js.js new file mode 100644 index 0000000..6ca9d9e --- /dev/null +++ b/patch_app_js.js @@ -0,0 +1,482 @@ +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); diff --git a/patch_turmas.js b/patch_turmas.js new file mode 100644 index 0000000..21edaa1 --- /dev/null +++ b/patch_turmas.js @@ -0,0 +1,297 @@ +const fs = require('fs'); +const path = require('path'); + +const serverFile = path.join(__dirname, 'server.js'); +let serverCode = fs.readFileSync(serverFile, 'utf8'); + +// Add tables to initDb +const tablesSql = ` + -- Turmas + CREATE TABLE IF NOT EXISTS escola.turmas ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + usuario_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', + nome VARCHAR(255) NOT NULL, + sala VARCHAR(255), + periodo VARCHAR(100), + prof_titular VARCHAR(255), + prof_aux1 VARCHAR(255), + prof_aux2 VARCHAR(255), + cuidadora VARCHAR(255), + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() + ); + + -- Alunos + CREATE TABLE IF NOT EXISTS escola.alunos ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + usuario_id UUID NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000', + turma_id UUID REFERENCES escola.turmas(id) ON DELETE CASCADE, + nome VARCHAR(255) NOT NULL, + apelido VARCHAR(255), + data_nasc DATE, + especial BOOLEAN DEFAULT false, + especial_detalhes TEXT, + pais TEXT, + autorizados TEXT, + created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() + ); +`; + +if (!serverCode.includes('CREATE TABLE IF NOT EXISTS escola.turmas')) { + serverCode = serverCode.replace( + "CREATE TABLE IF NOT EXISTS escola.estudio_musicas", + tablesSql + "\n CREATE TABLE IF NOT EXISTS escola.estudio_musicas" + ); +} + +// Add APIs before app.listen +const apiRoutes = ` +// ============================================================ +// CRUD TURMAS E ALUNOS (MINHA TURMA) +// ============================================================ +app.get('/api/turmas', requireAuth, async (req, res) => { + const usuarioId = req.cookies.usuario_id || req.headers['user-id'] || '00000000-0000-0000-0000-000000000000'; + try { + const dbRes = await dbPool.query("SELECT * FROM escola.turmas WHERE usuario_id = $1 ORDER BY created_at ASC;", [usuarioId]); + res.json(dbRes.rows); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.post('/api/turmas', requireAuth, async (req, res) => { + const usuarioId = req.cookies.usuario_id || req.headers['user-id'] || '00000000-0000-0000-0000-000000000000'; + const { nome, sala, periodo, profTitular, profAux1, profAux2, cuidadora } = req.body; + if (!nome) return res.status(400).json({ error: 'Nome é obrigatório' }); + try { + const dbRes = await dbPool.query( + "INSERT INTO escola.turmas (usuario_id, nome, sala, periodo, prof_titular, prof_aux1, prof_aux2, cuidadora) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *;", + [usuarioId, nome, sala, periodo, profTitular, profAux1, profAux2, cuidadora] + ); + res.status(201).json(dbRes.rows[0]); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.put('/api/turmas/:id', requireAuth, async (req, res) => { + const usuarioId = req.cookies.usuario_id || req.headers['user-id'] || '00000000-0000-0000-0000-000000000000'; + const { id } = req.params; + const { nome, sala, periodo, profTitular, profAux1, profAux2, cuidadora } = req.body; + if (!nome) return res.status(400).json({ error: 'Nome é obrigatório' }); + try { + const dbRes = await dbPool.query( + "UPDATE escola.turmas SET nome = $1, sala = $2, periodo = $3, prof_titular = $4, prof_aux1 = $5, prof_aux2 = $6, cuidadora = $7 WHERE id = $8 AND usuario_id = $9 RETURNING *;", + [nome, sala, periodo, profTitular, profAux1, profAux2, cuidadora, id, usuarioId] + ); + res.json(dbRes.rows[0]); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.delete('/api/turmas/:id', requireAuth, async (req, res) => { + const usuarioId = req.cookies.usuario_id || req.headers['user-id'] || '00000000-0000-0000-0000-000000000000'; + const { id } = req.params; + try { + await dbPool.query("DELETE FROM escola.turmas WHERE id = $1 AND usuario_id = $2;", [id, usuarioId]); + res.json({ success: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.get('/api/alunos', requireAuth, async (req, res) => { + const usuarioId = req.cookies.usuario_id || req.headers['user-id'] || '00000000-0000-0000-0000-000000000000'; + const { turma_id } = req.query; + try { + let query = "SELECT * FROM escola.alunos WHERE usuario_id = $1"; + let params = [usuarioId]; + if (turma_id) { + query += " AND turma_id = $2"; + params.push(turma_id); + } + query += " ORDER BY nome ASC;"; + const dbRes = await dbPool.query(query, params); + res.json(dbRes.rows); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.post('/api/alunos', requireAuth, async (req, res) => { + const usuarioId = req.cookies.usuario_id || req.headers['user-id'] || '00000000-0000-0000-0000-000000000000'; + const { turma_id, nome, apelido, data_nasc, especial, especial_detalhes, pais, autorizados } = req.body; + if (!nome || !turma_id) return res.status(400).json({ error: 'Nome e Turma são obrigatórios' }); + let nascDate = data_nasc ? data_nasc : null; + try { + const dbRes = await dbPool.query( + "INSERT INTO escola.alunos (usuario_id, turma_id, nome, apelido, data_nasc, especial, especial_detalhes, pais, autorizados) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *;", + [usuarioId, turma_id, nome, apelido, nascDate, especial, especial_detalhes, pais, autorizados] + ); + res.status(201).json(dbRes.rows[0]); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.put('/api/alunos/:id', requireAuth, async (req, res) => { + const usuarioId = req.cookies.usuario_id || req.headers['user-id'] || '00000000-0000-0000-0000-000000000000'; + const { id } = req.params; + const { turma_id, nome, apelido, data_nasc, especial, especial_detalhes, pais, autorizados } = req.body; + if (!nome || !turma_id) return res.status(400).json({ error: 'Nome e Turma são obrigatórios' }); + let nascDate = data_nasc ? data_nasc : null; + try { + const dbRes = await dbPool.query( + "UPDATE escola.alunos SET turma_id = $1, nome = $2, apelido = $3, data_nasc = $4, especial = $5, especial_detalhes = $6, pais = $7, autorizados = $8 WHERE id = $9 AND usuario_id = $10 RETURNING *;", + [turma_id, nome, apelido, nascDate, especial, especial_detalhes, pais, autorizados, id, usuarioId] + ); + res.json(dbRes.rows[0]); + } catch (err) { + res.status(500).json({ error: err.message }); + } +}); + +app.delete('/api/alunos/:id', requireAuth, async (req, res) => { + const usuarioId = req.cookies.usuario_id || req.headers['user-id'] || '00000000-0000-0000-0000-000000000000'; + const { id } = req.params; + try { + await dbPool.query("DELETE FROM escola.alunos WHERE id = $1 AND usuario_id = $2;", [id, usuarioId]); + res.json({ success: true }); + } catch (err) { + res.status(500).json({ error: err.message }); + } +});\n\n`; + +if (!serverCode.includes('app.get(\'/api/turmas\'')) { + serverCode = serverCode.replace("app.listen(PORT", apiRoutes + "app.listen(PORT"); +} +fs.writeFileSync(serverFile, serverCode); + + +// ========================================== +// Update index.html +// ========================================== +const indexFile = path.join(__dirname, 'public', 'index.html'); +let indexCode = fs.readFileSync(indexFile, 'utf8'); + +const newTurmaConfigHtml = ` + +
+ +
+
+

Minhas Turmas

+ +
+
+
Carregando turmas...
+
+
+ + +
+
+

Cadastrar Turma

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+
+`; + +const newTurmaAlunosHtml = ` + +