const SUPABASE_URL = 'YOUR_SUPABASE_URL'; const SUPABASE_KEY = 'YOUR_SUPABASE_KEY'; const IS_MOCK = SUPABASE_URL.includes('YOUR_SUPABASE'); let supabase; if (!IS_MOCK) { supabase = supabase.createClient(SUPABASE_URL, SUPABASE_KEY); } else { console.warn("⚠️ MOCK MODE ATIVADO: Usando LocalStorage. Configure o Supabase para persistência real."); showToast("Modo Demo Ativado (LocalStorage)", "warning"); } document.addEventListener('DOMContentLoaded', () => { checkLogin(); setupEventListeners(); }); function setupEventListeners() { document.getElementById('login-form').addEventListener('submit', handleLogin); document.getElementById('form-morador').addEventListener('submit', saveMorador); document.getElementById('form-transacao').addEventListener('submit', saveTransacao); document.getElementById('form-ocorrencia').addEventListener('submit', saveOcorrencia); document.getElementById('form-aviso').addEventListener('submit', saveAviso); if (sessionStorage.getItem('condoProUser')) { renderDashboard(); } } function checkLogin() { const user = sessionStorage.getItem('condoProUser'); if (user) { document.getElementById('login-section').classList.add('d-none'); document.getElementById('app-layout').classList.remove('d-none'); document.getElementById('app-layout').classList.add('d-flex'); } else { document.getElementById('login-section').classList.remove('d-none'); document.getElementById('app-layout').classList.add('d-none'); document.getElementById('app-layout').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) { if (IS_MOCK) { const data = JSON.parse(localStorage.getItem(`condopro_${table}`)) || []; if (orderBy) { data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); } return { data, error: null }; } let query = supabase.from(table).select('*'); if (orderBy) query = query.order(orderBy.col, { ascending: orderBy.asc }); return await query; } async function dbInsert(table, row) { row.created_at = new Date().toISOString(); if (!row.id) row.id = Date.now(); if (IS_MOCK) { const data = JSON.parse(localStorage.getItem(`condopro_${table}`)) || []; data.push(row); localStorage.setItem(`condopro_${table}`, JSON.stringify(data)); return { data: [row], error: null }; } return await supabase.from(table).insert([row]); } async function dbDelete(table, id) { if (IS_MOCK) { let data = JSON.parse(localStorage.getItem(`condopro_${table}`)) || []; data = data.filter(item => item.id != id); // Loose comparison for ID localStorage.setItem(`condopro_${table}`, JSON.stringify(data)); return { error: null }; } return await supabase.from(table).delete().eq('id', id); } 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 nome = document.getElementById('morador-nome').value; const bloco = document.getElementById('morador-bloco').value; const apartamento = document.getElementById('morador-apto').value; const telefone = document.getElementById('morador-telefone').value; const email = document.getElementById('morador-email').value; const { error } = await dbInsert('moradores', { nome, bloco, apartamento, telefone, email }); if (error) showToast("Erro ao salvar: " + error.message, "danger"); else { bootstrap.Modal.getInstance(document.getElementById('modalMorador')).hide(); renderMoradores(); showToast("Morador salvo com sucesso!", "success"); } } 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 (IS_MOCK && fileInput.files.length > 0) { showToast("Upload simulado (Mock Mode)", "info"); imagem_url = "https://placehold.co/600x400?text=Imagem+Ocorrencia"; } else if (fileInput.files.length > 0) { const file = fileInput.files[0]; const fileName = `${Date.now()}_${file.name}`; const { data, error } = await supabase.storage.from('condopro-bucket').upload(fileName, file); if (error) { showToast('Erro upload imagem: ' + error.message, "danger"); return; } const { data: publicData } = supabase.storage.from('condopro-bucket').getPublicUrl(fileName); imagem_url = publicData.publicUrl; } 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"); } import { db } from "./firebase.js"; import { collection, addDoc } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-firestore.js"; import { db } from "./firebase.js"; import { collection, addDoc } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-firestore.js"; document.getElementById("btnAdicionar").onclick = () => { document.getElementById("formCondominio").style.display = "block"; }; document.getElementById("guardar").onclick = async () => { const fracao = document.getElementById("fracao").value; const proprietario = document.getElementById("proprietario").value; const contacto = document.getElementById("contacto").value; try { await addDoc(collection(db, "condominios"), { fracao, proprietario, contacto, estado: "Pago", divida: 0 }); alert("Guardado com sucesso!"); } catch (e) { alert("Erro: " + e.message); } };