Implementação do banco de dados das Turmas e Alunos no Supabase e Refatoração do Modal de Cadastro

This commit is contained in:
2026-06-07 22:48:13 +00:00
parent a31764811b
commit 02d0c6fb86
5 changed files with 1238 additions and 159 deletions
+231 -116
View File
@@ -2989,19 +2989,36 @@ const initApp = () => {
};
// ============================================================
// MODAL: MINHA TURMA
// 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');
// Fields
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');
@@ -3011,22 +3028,45 @@ const initApp = () => {
const cFormPais = document.getElementById('childFormPais');
const cFormAutorizados = document.getElementById('childFormAutorizados');
// Fields Turma Config
// Tabs
const tabTurmaConfig = document.getElementById('tabTurmaConfig');
const tabTurmaAlunos = document.getElementById('tabTurmaAlunos');
const turmaConfigSection = document.getElementById('turmaConfigSection');
const turmaAlunosSection = document.getElementById('turmaAlunosSection');
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 btnSaveTurmaConfig = document.getElementById('btnSaveTurmaConfig');
// Tab Logic
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 = '<option value="">Todas as Turmas</option>' + currentTurmas.map(t => `<option value="${t.id}">${t.nome}</option>`).join('');
if(filterAlunosTurma) filterAlunosTurma.innerHTML = opts;
const formOpts = '<option value="">Selecione uma turma...</option>' + currentTurmas.map(t => `<option value="${t.id}">${t.nome}</option>`).join('');
if(cFormTurma) cFormTurma.innerHTML = formOpts;
if(document.getElementById('emitirFilterTurma')) {
document.getElementById('emitirFilterTurma').innerHTML = '<option value="">Todas as turmas</option>' + currentTurmas.map(t => `<option value="${t.id}">${t.nome}</option>`).join('');
}
};
// Tabs Logic
if (tabTurmaConfig) {
tabTurmaConfig.addEventListener('click', () => {
tabTurmaConfig.classList.add('active');
@@ -3052,86 +3092,109 @@ const initApp = () => {
});
}
// Toggle Especial Fields
if (cFormEspecial) {
cFormEspecial.addEventListener('change', () => {
if (cFormEspecial.checked) {
divEspecialDetalhes.style.display = 'flex';
} else {
divEspecialDetalhes.style.display = 'none';
}
});
}
const loadTurma = () => {
return JSON.parse(localStorage.getItem('camila_turma') || '[]');
// 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 saveTurma = (turma) => {
localStorage.setItem('camila_turma', JSON.stringify(turma));
const renderTurmasList = () => {
if(!turmasList) return;
if(currentTurmas.length === 0) {
turmasList.innerHTML = '<div style="color: var(--text-secondary); text-align: center; padding: 20px;">Nenhuma turma cadastrada.</div>';
return;
}
turmasList.innerHTML = currentTurmas.map(t => `
<div style="background: var(--bg-secondary); border: 1px solid var(--border-light); padding: 12px; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
<div>
<div style="font-weight: 600; color: var(--text-primary);">${escapeHtml(t.nome)}</div>
<div style="font-size: 0.8rem; color: var(--text-secondary);">${t.periodo || ''} ${t.sala ? '- ' + t.sala : ''}</div>
</div>
<div style="display: flex; gap: 8px;">
<button onclick="editTurma('${t.id}')" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; padding: 4px;" title="Editar"></button>
<button onclick="deleteTurma('${t.id}')" style="background: none; border: none; color: #ef4444; cursor: pointer; padding: 4px;" title="Excluir">🗑</button>
</div>
</div>
`).join('');
};
const loadTurmaConfig = () => {
return JSON.parse(localStorage.getItem('camila_config_turma') || '{}');
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';
};
const saveTurmaConfig = (cfg) => {
localStorage.setItem('camila_config_turma', JSON.stringify(cfg));
showCustomAlert('Sucesso', 'Configurações da turma salvas com sucesso!');
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', () => {
saveTurmaConfig({
nome: configTurmaNome.value,
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); }
});
}
const populateTurmaConfig = () => {
const cfg = loadTurmaConfig();
if(configTurmaNome) configTurmaNome.value = cfg.nome || '';
if(configTurmaSala) configTurmaSala.value = cfg.sala || '';
if(configTurmaPeriodo) configTurmaPeriodo.value = cfg.periodo || 'Integral';
if(configTurmaProfTitular) configTurmaProfTitular.value = cfg.profTitular || '';
if(configTurmaProfAux1) configTurmaProfAux1.value = cfg.profAux1 || '';
if(configTurmaProfAux2) configTurmaProfAux2.value = cfg.profAux2 || '';
if(configTurmaCuidadora) configTurmaCuidadora.value = cfg.cuidadora || '';
};
const renderTurmaList = () => {
if (!childrenList) return;
const turma = loadTurma();
if (turma.length === 0) {
childrenList.innerHTML = '<div style="color: var(--text-secondary); text-align: center; padding: 20px;">Nenhuma criança cadastrada.</div>';
return;
}
// Sort by name
turma.sort((a, b) => (a.nome || '').localeCompare(b.nome || ''));
childrenList.innerHTML = turma.map(c => `
<div style="background: var(--bg-secondary); border: 1px solid var(--border-light); padding: 12px; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
<div>
<div style="font-weight: 600; color: var(--text-primary);">${escapeHtml(c.nome)} ${c.especial ? '⭐' : ''}</div>
<div style="font-size: 0.8rem; color: var(--text-secondary);">${escapeHtml(c.apelido || '')}</div>
</div>
<div style="display: flex; gap: 8px;">
<button onclick="editChild('${c.id}')" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; padding: 4px;" title="Editar"></button>
<button onclick="deleteChild('${c.id}')" style="background: none; border: none; color: #ef4444; cursor: pointer; padding: 4px;" title="Excluir">🗑</button>
</div>
</div>
`).join('');
};
// Alunos Logic
const clearChildForm = () => {
cFormId.value = '';
cFormTurma.value = filterAlunosTurma ? filterAlunosTurma.value : '';
cFormNome.value = '';
cFormApelido.value = '';
cFormDataNasc.value = '';
@@ -3143,17 +3206,66 @@ const initApp = () => {
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 = '<div style="color: var(--text-secondary); text-align: center; padding: 20px;">Nenhuma criança encontrada.</div>';
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 `
<div style="background: var(--bg-secondary); border: 1px solid var(--border-light); padding: 12px; border-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
<div>
<div style="font-weight: 600; color: var(--text-primary);">${escapeHtml(c.nome)} ${c.especial ? '⭐' : ''}</div>
<div style="font-size: 0.8rem; color: var(--text-secondary);">${escapeHtml(turmaNome)} ${c.apelido ? '- ' + escapeHtml(c.apelido) : ''}</div>
</div>
<div style="display: flex; gap: 8px;">
<button onclick="editChild('${c.id}')" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; padding: 4px;" title="Editar"></button>
<button onclick="deleteChild('${c.id}')" style="background: none; border: none; color: #ef4444; cursor: pointer; padding: 4px;" title="Excluir">🗑</button>
</div>
</div>
`}).join('');
};
if(filterAlunosTurma) {
filterAlunosTurma.addEventListener('change', () => {
renderAlunosList();
if(cFormTurma) cFormTurma.value = filterAlunosTurma.value;
});
}
window.editChild = (id) => {
const turma = loadTurma();
const c = turma.find(x => x.id === 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 || '';
cFormDataNasc.value = c.dataNasc || '';
if(c.data_nasc) {
cFormDataNasc.value = c.data_nasc.split('T')[0];
} else {
cFormDataNasc.value = '';
}
cFormEspecial.checked = !!c.especial;
cFormEspecialDetalhes.value = c.especialDetalhes || '';
cFormEspecialDetalhes.value = c.especial_detalhes || '';
divEspecialDetalhes.style.display = c.especial ? 'flex' : 'none';
cFormPais.value = c.pais || '';
cFormAutorizados.value = c.autorizados || '';
@@ -3162,21 +3274,23 @@ const initApp = () => {
};
window.deleteChild = async (id) => {
const isOk = await showCustomConfirm('Excluir', 'Deseja excluir esta criança? Isso não removerá as observações já feitas, apenas removerá da lista da turma.', true);
const isOk = await showCustomConfirm('Excluir', 'Deseja excluir esta criança? Isso não removerá as observações já feitas.', true);
if (isOk) {
let turma = loadTurma();
turma = turma.filter(x => x.id !== id);
saveTurma(turma);
renderTurmaList();
await fetch('/api/alunos/' + id, { method: 'DELETE' });
await fetchAlunos();
renderAlunosList();
clearChildForm();
}
};
if (btnMinhaTurma) {
btnMinhaTurma.addEventListener('click', () => {
btnMinhaTurma.addEventListener('click', async () => {
minhaTurmaModal.style.display = 'flex';
populateTurmaConfig();
renderTurmaList();
await fetchTurmas();
await fetchAlunos();
renderTurmasList();
renderAlunosList();
clearTurmaForm();
clearChildForm();
});
}
@@ -3192,42 +3306,48 @@ const initApp = () => {
if (btnCancelChild) btnCancelChild.addEventListener('click', clearChildForm);
if (btnSaveChild) {
btnSaveChild.addEventListener('click', () => {
if (!cFormNome.value.trim()) {
showCustomAlert('Aviso', 'O Nome Completo é obrigatório.');
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;
}
let turma = loadTurma();
const id = cFormId.value || 'child_' + Date.now();
const newChild = {
id,
const id = cFormId.value;
const body = {
turma_id: cFormTurma.value,
nome: cFormNome.value.trim(),
apelido: cFormApelido.value.trim(),
dataNasc: cFormDataNasc.value,
data_nasc: cFormDataNasc.value || null,
especial: cFormEspecial.checked,
especialDetalhes: cFormEspecialDetalhes.value.trim(),
especial_detalhes: cFormEspecialDetalhes.value.trim(),
pais: cFormPais.value.trim(),
autorizados: cFormAutorizados.value.trim()
};
const idx = turma.findIndex(x => x.id === id);
if (idx > -1) {
turma[idx] = newChild;
} else {
turma.push(newChild);
}
saveTurma(turma);
renderTurmaList();
clearChildForm();
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) {
if (btnVoiceRecordChild && (window.SpeechRecognition || window.webkitSpeechRecognition)) {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const formRecognition = new SpeechRecognition();
formRecognition.lang = 'pt-BR';
@@ -3254,7 +3374,7 @@ const initApp = () => {
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", "dataNasc" (formato YYYY-MM-DD), "especial" (boolean), "especialDetalhes", "pais", "autorizados".
"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
@@ -3264,20 +3384,15 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
if (response.ok) {
const data = await response.json();
const assistantReply = data.message;
// Extract JSON block
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.turma) cFormTurma.value = parsed.turma;
if (parsed.sala) cFormSala.value = parsed.sala;
if (parsed.periodo) cFormPeriodo.value = parsed.periodo;
if (parsed.auxiliares) cFormAuxiliares.value = parsed.auxiliares;
if (parsed.nome) cFormNome.value = parsed.nome;
if (parsed.apelido) cFormApelido.value = parsed.apelido;
if (parsed.dataNasc) cFormDataNasc.value = parsed.dataNasc;
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.especialDetalhes) cFormEspecialDetalhes.value = parsed.especialDetalhes;
if (parsed.especial_detalhes) cFormEspecialDetalhes.value = parsed.especial_detalhes;
if (parsed.pais) cFormPais.value = parsed.pais;
if (parsed.autorizados) cFormAutorizados.value = parsed.autorizados;
}
@@ -3336,7 +3451,7 @@ Se algum dado não for mencionado, deixe a string vazia ou false para boolean.`
});
};
// ============================================================
// // ============================================================
// CRUD DE MODELOS DE RELATÓRIO
// ============================================================
const modelosRelatorioModal = document.getElementById('modelosRelatorioModal');
+80 -43
View File
@@ -536,64 +536,91 @@
<div class="settings-modal-body" style="padding: 16px; overflow: hidden; display: flex; flex-direction: column; flex: 1; min-height: 500px;">
<!-- SECÃO 1: CONFIGURAÇÕES DA TURMA -->
<div id="turmaConfigSection" style="display: flex; flex-direction: column; gap: 16px; flex: 1; width: 100%; overflow-y: auto; padding-right: 8px;">
<h4 style="margin: 0; color: var(--text-primary);">Configurações e Equipe da Turma</h4>
<p style="margin: 0; font-size: 0.85rem; color: var(--text-secondary);">Defina as informações gerais da turma. Estas informações valem para todos os alunos e serão usadas nos relatórios.</p>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
<div class="settings-group">
<label>Nome da Turma</label>
<input type="text" id="configTurmaNome" placeholder="Ex: Berçário 2" class="obs-input" style="width: 100%;">
<!-- SECÃO 1: TURMAS (Múltiplas turmas) -->
<div id="turmaConfigSection" style="display: flex; flex-direction: row; gap: 16px; flex: 1; height: 100%; overflow: hidden;">
<!-- Lado Esquerdo: Lista de Turmas -->
<div style="flex: 1; border-right: 1px solid var(--border-light); padding-right: 16px; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; height: 100%;">
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border-light); padding-bottom: 8px;">
<h4 style="margin: 0; color: var(--text-primary);">Minhas Turmas</h4>
<button id="btnCreateTurma" style="background: var(--brand-green); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 0.85rem; font-weight: 600; cursor: pointer;">+ Nova Turma</button>
</div>
<div class="settings-group">
<label>Sala</label>
<input type="text" id="configTurmaSala" placeholder="Ex: Sala 4" class="obs-input" style="width: 100%;">
</div>
<div class="settings-group">
<label>Período</label>
<select id="configTurmaPeriodo" class="obs-select" style="width: 100%;">
<option value="Integral">Integral</option>
<option value="Matutino">Matutino</option>
<option value="Vespertino">Vespertino</option>
</select>
<div id="turmasList" style="display: flex; flex-direction: column; gap: 8px;">
<div style="color: var(--text-secondary); text-align: center; padding: 20px;">Carregando turmas...</div>
</div>
</div>
<!-- Lado Direito: Form Turma -->
<div id="turmaFormContainer" style="flex: 1.5; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; padding-left: 4px;">
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border-light); padding-bottom: 8px;">
<h4 id="turmaFormTitle" style="margin: 0; color: var(--text-primary);">Cadastrar Turma</h4>
</div>
<input type="hidden" id="configTurmaId">
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px;">
<div class="settings-group">
<label>Nome da Turma</label>
<input type="text" id="configTurmaNome" placeholder="Ex: Berçário 2" class="obs-input" style="width: 100%;">
</div>
<div class="settings-group">
<label>Sala</label>
<input type="text" id="configTurmaSala" placeholder="Ex: Sala 4" class="obs-input" style="width: 100%;">
</div>
<div class="settings-group">
<label>Período</label>
<select id="configTurmaPeriodo" class="obs-select" style="width: 100%;">
<option value="Integral">Integral</option>
<option value="Matutino">Matutino</option>
<option value="Vespertino">Vespertino</option>
</select>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; border-top: 1px solid var(--border-light); padding-top: 16px;">
<div class="settings-group">
<label>Professora Titular</label>
<input type="text" id="configTurmaProfTitular" placeholder="Sua Titulação e Nome" class="obs-input" style="width: 100%;">
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; border-top: 1px solid var(--border-light); padding-top: 16px;">
<div class="settings-group">
<label>Professora Titular</label>
<input type="text" id="configTurmaProfTitular" placeholder="Sua Titulação e Nome" class="obs-input" style="width: 100%;">
</div>
<div class="settings-group">
<label>Professora Auxiliar 1</label>
<input type="text" id="configTurmaProfAux1" placeholder="Nome da Prof. Auxiliar" class="obs-input" style="width: 100%;">
</div>
<div class="settings-group">
<label>Professora Auxiliar 2</label>
<input type="text" id="configTurmaProfAux2" placeholder="Nome da Prof. Auxiliar (Opcional)" class="obs-input" style="width: 100%;">
</div>
<div class="settings-group">
<label>Cuidadora</label>
<input type="text" id="configTurmaCuidadora" placeholder="Nome da Cuidadora (Opcional)" class="obs-input" style="width: 100%;">
</div>
</div>
<div class="settings-group">
<label>Professora Auxiliar 1</label>
<input type="text" id="configTurmaProfAux1" placeholder="Nome da Prof. Auxiliar" class="obs-input" style="width: 100%;">
</div>
<div class="settings-group">
<label>Professora Auxiliar 2</label>
<input type="text" id="configTurmaProfAux2" placeholder="Nome da Prof. Auxiliar (Opcional)" class="obs-input" style="width: 100%;">
</div>
<div class="settings-group">
<label>Cuidadora</label>
<input type="text" id="configTurmaCuidadora" placeholder="Nome da Cuidadora (Opcional)" class="obs-input" style="width: 100%;">
</div>
</div>
<div style="display: flex; gap: 8px; justify-content: flex-end; border-top: 1px solid var(--border-light); padding-top: 16px; margin-top: auto;">
<button id="btnSaveTurmaConfig" style="background: var(--brand-green); border: none; color: white; padding: 10px 20px; border-radius: 8px; font-weight: 600; cursor: pointer; font-size: 0.95rem;">Salvar Dados da Turma</button>
<div style="display: flex; gap: 8px; justify-content: flex-end; border-top: 1px solid var(--border-light); padding-top: 16px; margin-top: auto;">
<button id="btnCancelTurma" style="background: none; border: 1px solid var(--border-light); color: var(--text-secondary); padding: 8px 16px; border-radius: 8px; cursor: pointer; font-size: 0.9rem;">Cancelar</button>
<button id="btnSaveTurmaConfig" style="background: var(--brand-green); border: none; color: white; padding: 10px 20px; border-radius: 8px; font-weight: 600; cursor: pointer; font-size: 0.95rem;">Salvar Turma</button>
</div>
</div>
</div>
<!-- SECÃO 2: ALUNOS DA TURMA -->
<div id="turmaAlunosSection" style="display: none; flex-direction: row; gap: 16px; flex: 1; height: 100%; overflow: hidden;">
<!-- Lado Esquerdo: Lista de Crianças -->
<!-- Lado Esquerdo: Lista de Crianças e Filtro -->
<div style="flex: 1; border-right: 1px solid var(--border-light); padding-right: 16px; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; height: 100%;">
<div style="display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid var(--border-light); padding-bottom: 8px;">
<h4 style="margin: 0; color: var(--text-primary);">Lista de Crianças</h4>
<button id="btnCreateChild" style="background: var(--brand-green); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 0.85rem; font-weight: 600; cursor: pointer; transition: opacity 0.2s;">+ Nova Criança</button>
<div style="display: flex; flex-direction: column; gap: 8px; border-bottom: 1px solid var(--border-light); padding-bottom: 8px;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<h4 style="margin: 0; color: var(--text-primary);">Lista de Crianças</h4>
<button id="btnCreateChild" style="background: var(--brand-green); color: white; border: none; padding: 6px 12px; border-radius: 6px; font-size: 0.85rem; font-weight: 600; cursor: pointer; transition: opacity 0.2s;">+ Nova Criança</button>
</div>
<div class="settings-group" style="margin-bottom: 0;">
<select id="filterAlunosTurma" class="obs-select" style="width: 100%; padding: 6px;">
<option value="">Todas as Turmas</option>
</select>
</div>
</div>
<div id="childrenList" style="display: flex; flex-direction: column; gap: 8px;">
<!-- Carregado via JS -->
<div style="color: var(--text-secondary); text-align: center; padding: 20px;">Carregando turma...</div>
<div style="color: var(--text-secondary); text-align: center; padding: 20px;">Carregando alunos...</div>
</div>
</div>
@@ -607,6 +634,16 @@
</div>
<input type="hidden" id="childFormId">
<div class="settings-group" style="gap: 4px;">
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Turma do Aluno</label>
<select id="childFormTurma" class="obs-select" style="width: 100%;"></select>
</div>
<div class="settings-group" style="gap: 4px;">
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Nome Completo da Criança</label>
<input type="text" id="childFormNome" placeholder="Ex: João da Silva" class="obs-input" style="width: 100%;">
</div>
<div class="settings-group" style="gap: 4px;">
<label style="color: var(--text-secondary); font-size: 0.8rem; font-weight: 500;">Nome Completo da Criança</label>
<input type="text" id="childFormNome" placeholder="Ex: João da Silva" class="obs-input" style="width: 100%;">