import { db } from "./firebase.js"; import { ref, get, set, remove, push, onValue } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-database.js"; console.log("Integração com Firebase Database Iniciada"); document.addEventListener('DOMContentLoaded', () => { checkLogin(); setupEventListeners(); }); function setupEventListeners() { const loginForm = document.getElementById('login-form'); if (loginForm) loginForm.addEventListener('submit', handleLogin); const formMorador = document.getElementById('form-morador'); if (formMorador) formMorador.addEventListener('submit', saveMorador); const formTransacao = document.getElementById('form-transacao'); if (formTransacao) formTransacao.addEventListener('submit', saveTransacao); const formOcorrencia = document.getElementById('form-ocorrencia'); if (formOcorrencia) formOcorrencia.addEventListener('submit', saveOcorrencia); const formAviso = document.getElementById('form-aviso'); if (formAviso) formAviso.addEventListener('submit', saveAviso); listenCondominos(); // Inicia o listener realtime para os condóminos if (sessionStorage.getItem('condoProUser')) { renderDashboard(); } } function checkLogin() { const user = sessionStorage.getItem('condoProUser'); const loginSection = document.getElementById('login-section'); const appLayout = document.getElementById('app-layout'); if (user) { if (loginSection) loginSection.classList.add('d-none'); if (appLayout) { appLayout.classList.remove('d-none'); appLayout.classList.add('d-flex'); } } else { if (loginSection) loginSection.classList.remove('d-none'); if (appLayout) { appLayout.classList.add('d-none'); appLayout.classList.remove('d-flex'); } } } function handleLogin(e) { e.preventDefault(); const pass = document.getElementById('login-password').value; if (pass === 'admin123') { sessionStorage.setItem('condoProUser', 'admin'); checkLogin(); renderDashboard(); showToast("Bem-vindo ao CondoPro!", "success"); } else { document.getElementById('login-error').classList.remove('d-none'); showToast("Senha incorreta!", "danger"); } } function logout() { sessionStorage.removeItem('condoProUser'); checkLogin(); showToast("Logout realizado.", "info"); } function showToast(message, type = 'primary') { const container = document.getElementById('toast-container'); const toastEl = document.createElement('div'); toastEl.className = `toast align-items-center text-white bg-${type} border-0`; toastEl.setAttribute('role', 'alert'); toastEl.setAttribute('aria-live', 'assertive'); toastEl.setAttribute('aria-atomic', 'true'); toastEl.innerHTML = `
${message}
`; container.appendChild(toastEl); const toast = new bootstrap.Toast(toastEl, { delay: 3000 }); toast.show(); toastEl.addEventListener('hidden.bs.toast', () => { toastEl.remove(); }); } async function dbSelect(table, orderBy = null) { try { const snapshot = await get(ref(db, table)); const data = []; if (snapshot.exists()) { snapshot.forEach((childSnapshot) => { const item = childSnapshot.val(); item.id = childSnapshot.key; data.push(item); }); } if (orderBy) { data.sort((a, b) => { let valA = a[orderBy.col]; let valB = b[orderBy.col]; if (valA < valB) return orderBy.asc ? -1 : 1; if (valA > valB) return orderBy.asc ? 1 : -1; return 0; }); } return { data, error: null }; } catch (error) { return { data: null, error }; } } async function dbInsert(table, row) { try { row.created_at = new Date().toISOString(); if (!row.id) row.id = Date.now().toString(); await set(ref(db, `${table}/${row.id}`), row); return { data: [row], error: null }; } catch (error) { console.error("Erro no dbInsert:", error); return { data: null, error }; } } async function dbDelete(table, id) { try { await remove(ref(db, `${table}/${id}`)); return { error: null }; } catch (error) { return { error }; } } function navigateTo(viewId) { document.querySelectorAll('.nav-link').forEach(link => link.classList.remove('active')); event.currentTarget.classList.add('active'); document.querySelectorAll('.content-view').forEach(view => view.classList.add('d-none')); document.getElementById(`view-${viewId}`).classList.remove('d-none'); if (viewId === 'dashboard') renderDashboard(); if (viewId === 'moradores') renderMoradores(); if (viewId === 'financeiro') renderFinanceiro(); if (viewId === 'ocorrencias') renderOcorrencias(); if (viewId === 'avisos') renderAvisos(); document.getElementById('sidebar').classList.remove('show'); } function toggleSidebar() { document.getElementById('sidebar').classList.toggle('show'); } let financeChartInstance = null; async function renderDashboard() { const { data: financeiro } = await dbSelect('financeiro'); const { data: moradores } = await dbSelect('moradores'); const { data: ocorrencias } = await dbSelect('ocorrencias'); let saldoTotal = 0; let receitasMes = 0; let despesasMes = 0; if (financeiro) { financeiro.forEach(t => { const val = parseFloat(t.valor); if (t.tipo === 'receita') { saldoTotal += val; receitasMes += val; } else { saldoTotal -= val; despesasMes += val; } }); } const ocorrenciasPendentes = ocorrencias ? ocorrencias.filter(o => o.status === 'pendente').length : 0; document.getElementById('dash-saldo').innerText = `R$ ${saldoTotal.toFixed(2)}`; document.getElementById('dash-receitas').innerText = `R$ ${receitasMes.toFixed(2)}`; document.getElementById('dash-despesas').innerText = `R$ ${despesasMes.toFixed(2)}`; document.getElementById('dash-moradores-count').innerText = moradores ? moradores.length : 0; document.getElementById('dash-ocorrencias-count').innerText = ocorrenciasPendentes; renderChart(financeiro || []); } function renderChart(transactions) { const ctx = document.getElementById('financeChart').getContext('2d'); if (financeChartInstance) financeChartInstance.destroy(); const labels = ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun']; const dataReceitas = [0, 0, 0, 0, 0, 0]; const dataDespesas = [0, 0, 0, 0, 0, 0]; if (transactions.length > 0) { dataReceitas[5] = transactions.filter(t => t.tipo === 'receita').reduce((a, b) => a + parseFloat(b.valor), 0); dataDespesas[5] = transactions.filter(t => t.tipo === 'despesa').reduce((a, b) => a + parseFloat(b.valor), 0); } else { dataReceitas.splice(0, 6, 1200, 1500, 1100, 1800, 2000, 2200); dataDespesas.splice(0, 6, 800, 900, 700, 1000, 950, 1100); } financeChartInstance = new Chart(ctx, { type: 'bar', data: { labels: labels, datasets: [ { label: 'Receitas', data: dataReceitas, backgroundColor: '#2ecc71', borderRadius: 4 }, { label: 'Despesas', data: dataDespesas, backgroundColor: '#e74c3c', borderRadius: 4 } ] }, options: { responsive: true, plugins: { legend: { position: 'bottom' } }, scales: { y: { beginAtZero: true, grid: { color: 'rgba(0,0,0,0.05)' } }, x: { grid: { display: false } } } } }); } async function renderMoradores() { const tbody = document.getElementById('moradores-list'); tbody.innerHTML = 'Carregando...'; const { data, error } = await dbSelect('moradores'); if (error) { tbody.innerHTML = 'Erro ao carregar dados.'; showToast("Erro ao carregar moradores", "danger"); return; } tbody.innerHTML = ''; if (data.length === 0) { tbody.innerHTML = 'Nenhum morador cadastrado.'; return; } data.forEach(m => { const tr = document.createElement('tr'); tr.innerHTML = `
${m.nome}
${m.email || ''} ${m.bloco} ${m.apartamento} ${m.telefone || '-'} `; tbody.appendChild(tr); }); } function prepareCreateMorador() { document.getElementById('form-morador').reset(); } async function saveMorador(e) { e.preventDefault(); const fracaoInput = document.getElementById("fracao"); const proprietarioInput = document.getElementById("proprietario"); const contactoInput = document.getElementById("contacto"); // Fallback para formulário legado caso os IDs sejam diferentes const fracao = fracaoInput ? fracaoInput.value.trim() : document.getElementById("morador-fracao")?.value.trim(); const proprietario = proprietarioInput ? proprietarioInput.value.trim() : document.getElementById("morador-nome")?.value.trim(); const contacto = contactoInput ? contactoInput.value.trim() : document.getElementById("morador-contacto")?.value.trim(); // Obter estado, assumindo um seletor ou predefinição const estadoInput = document.getElementById("estado"); const estado = estadoInput ? estadoInput.value : "Pago"; // Validação Básica if (!fracao || !proprietario || !contacto) { alert("Por favor, preenche todos os campos obrigatórios (fração, proprietário e contacto)."); return; } try { // Gerar um novo ID automaticamente usando push() const condominiosRef = ref(db, "condominos"); await push(condominiosRef, { fracao, proprietario, contacto, estado: estado, divida: estado === "Pago" ? 0 : 50 // Lógica de exemplo }); // Limpar o formulário const form = document.getElementById('form-morador') || document.getElementById('formCondominio'); if (form) form.reset(); else { if(fracaoInput) fracaoInput.value = ''; if(proprietarioInput) proprietarioInput.value = ''; if(contactoInput) contactoInput.value = ''; } if (typeof showToast === "function") { showToast("Condómino adicionado com sucesso!", "success"); } else { alert("Condómino guardado com sucesso!"); } } catch (erro) { console.error("Erro ao guardar no Firebase: ", erro); alert("Ocorreu um erro ao guardar o condómino."); } } // Função para atualizar automaticamente a lista function listenCondominos() { const condominiosRef = ref(db, "condominos"); // onValue reage sempre que há mudanças na base de dados (adicionar, editar, remover) onValue(condominiosRef, (snapshot) => { const data = snapshot.val(); // Se houver uma função render reactiva no Vanilla, chamamo-la aqui. // Exemplo: renderCondominosLista(data); console.log("Dados atualizados em tempo real:", data); // Exemplo básico de atualização de DOM se tivermos uma tabela const tbody = document.getElementById('moradores-list'); if (tbody && data) { tbody.innerHTML = ''; Object.entries(data).forEach(([id, m]) => { const tr = document.createElement('tr'); tr.innerHTML = `
${m.proprietario || 'Sem Nome'}
${m.fracao || '-'} ${m.contacto || '-'} ${m.estado || 'Pago'} `; tbody.appendChild(tr); }); } }); } async function renderFinanceiro() { const tbody = document.getElementById('financeiro-list'); tbody.innerHTML = 'Carregando...'; const { data, error } = await dbSelect('financeiro', { col: 'created_at', asc: false }); if (error) { tbody.innerHTML = 'Erro ao carregar.'; return; } tbody.innerHTML = ''; if (data.length === 0) { tbody.innerHTML = 'Nenhuma transação encontrada.'; return; } data.forEach(t => { const tr = document.createElement('tr'); const badgeClass = t.tipo === 'receita' ? 'bg-success' : 'bg-danger'; const icon = t.tipo === 'receita' ? 'fa-arrow-up' : 'fa-arrow-down'; tr.innerHTML = ` ${new Date(t.data).toLocaleDateString()} ${t.descricao} ${t.tipo.toUpperCase()} R$ ${parseFloat(t.valor).toFixed(2)} `; tbody.appendChild(tr); }); } function prepareCreateTransacao() { document.getElementById('form-transacao').reset(); } async function saveTransacao(e) { e.preventDefault(); const descricao = document.getElementById('transacao-descricao').value; const tipo = document.getElementById('transacao-tipo').value; const valor = document.getElementById('transacao-valor').value; const data = document.getElementById('transacao-data').value; const { error } = await dbInsert('financeiro', { descricao, tipo, valor, data }); if (error) showToast("Erro: " + error.message, "danger"); else { bootstrap.Modal.getInstance(document.getElementById('modalTransacao')).hide(); renderFinanceiro(); showToast("Transação registrada!", "success"); } } async function renderOcorrencias() { const container = document.getElementById('ocorrencias-list'); const { data, error } = await dbSelect('ocorrencias', { col: 'created_at', asc: false }); if (error) { container.innerHTML = '

Erro ao carregar

'; return; } container.innerHTML = ''; if (data.length === 0) { container.innerHTML = '

Nenhuma ocorrência pendente.

'; return; } data.forEach(o => { const card = document.createElement('div'); card.className = 'col-md-4 mb-4 fade-in'; card.innerHTML = `
${o.imagem_url ? `Ocorrência` : ''}
${o.titulo}
Pendente

${o.descricao}

${new Date(o.created_at).toLocaleDateString()}
`; container.appendChild(card); }); } function prepareCreateOcorrencia() { document.getElementById('form-ocorrencia').reset(); } async function saveOcorrencia(e) { e.preventDefault(); const titulo = document.getElementById('ocorrencia-titulo').value; const descricao = document.getElementById('ocorrencia-descricao').value; const fileInput = document.getElementById('ocorrencia-file'); let imagem_url = null; if (fileInput.files.length > 0) { showToast("Upload simulado (Firebase Storage não configurado)", "info"); imagem_url = "https://placehold.co/600x400?text=Imagem+Ocorrencia"; } const { error } = await dbInsert('ocorrencias', { titulo, descricao, imagem_url, status: 'pendente' }); if (error) showToast("Erro: " + error.message, "danger"); else { bootstrap.Modal.getInstance(document.getElementById('modalOcorrencia')).hide(); renderOcorrencias(); showToast("Ocorrência reportada!", "success"); } } async function resolveOcorrencia(id) { await dbDelete('ocorrencias', id); renderOcorrencias(); showToast("Ocorrência marcada como resolvida!", "success"); } async function renderAvisos() { const list = document.getElementById('avisos-list'); const { data, error } = await dbSelect('avisos', { col: 'created_at', asc: false }); if (error) { list.innerHTML = 'Erro ao carregar'; return; } list.innerHTML = ''; if (data.length === 0) { list.innerHTML = '

Nenhum aviso no mural.

'; return; } data.forEach(a => { const item = document.createElement('a'); item.className = 'list-group-item list-group-item-action flex-column align-items-start border-start border-4 border-info shadow-sm mb-2'; item.innerHTML = `
${a.titulo}
${new Date(a.created_at).toLocaleDateString()}

${a.mensagem}

`; list.appendChild(item); }); } function prepareCreateAviso() { document.getElementById('form-aviso').reset(); } async function saveAviso(e) { e.preventDefault(); const titulo = document.getElementById('aviso-titulo').value; const mensagem = document.getElementById('aviso-mensagem').value; const { error } = await dbInsert('avisos', { titulo, mensagem }); if (error) showToast("Erro: " + error.message, "danger"); else { bootstrap.Modal.getInstance(document.getElementById('modalAviso')).hide(); renderAvisos(); showToast("Aviso publicado!", "info"); } } async function deleteItem(table, id) { if (confirm('Tem certeza que deseja excluir?')) { const { error } = await dbDelete(table, id); if (error) showToast("Erro ao excluir", "danger"); else { showToast("Item excluído.", "success"); if (table === 'moradores') renderMoradores(); if (table === 'financeiro') renderFinanceiro(); } } } function exportPDF(tableId, filename) { const { jsPDF } = window.jspdf; const doc = new jsPDF(); doc.text(filename.replace('_', ' '), 14, 15); doc.autoTable({ html: '#' + tableId, startY: 20 }); doc.save(filename + '.pdf'); showToast("PDF gerado com sucesso!", "success"); } const guardarBtn = document.getElementById("guardar"); if (guardarBtn) { guardarBtn.onclick = async () => { const fracao = document.getElementById("fracao")?.value; const proprietario = document.getElementById("proprietario")?.value; const contacto = document.getElementById("contacto")?.value; console.log("A tentar guardar no Firebase..."); try { await push(ref(db, "condominios"), { fracao, proprietario, contacto }); alert("Guardado com sucesso!"); } catch (e) { alert("Erro: " + e.message); } }; }