adicionar condóminos

This commit is contained in:
2026-04-23 10:40:57 +01:00
parent 842dd08f73
commit c251549f63
4 changed files with 181 additions and 105 deletions

View File

@@ -1,3 +1,3 @@
{ {
"liveServer.settings.port": 5503 "liveServer.settings.port": 5504
} }

View File

@@ -1,16 +1,18 @@
import { initializeApp } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-app.js"; import { initializeApp } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-app.js";
import { getFirestore } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-firestore.js"; import { getDatabase } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-database.js";
const firebaseConfig = { const firebaseConfig = {
apiKey: "SUA_API_KEY", apiKey: "AQUI_TUA_API_KEY",
authDomain: "SEU_PROJETO.firebaseapp.com", authDomain: "AQUI.firebaseapp.com",
projectId: "SEU_PROJECT_ID", databaseURL: "https://condomaster-pro-ed9af-default-rtdb.europe-west1.firebasedatabase.app",
storageBucket: "SEU_PROJETO.appspot.com", projectId: "condomaster-pro-ed9af",
messagingSenderId: "SEU_ID", storageBucket: "condomaster-pro-ed9af.appspot.com",
appId: "SEU_APP_ID" messagingSenderId: "AQUI",
appId: "AQUI"
}; };
const app = initializeApp(firebaseConfig); const app = initializeApp(firebaseConfig);
const db = getFirestore(app); const db = getDatabase(app);
export { app, db };
export { db };

View File

@@ -98,6 +98,10 @@
Dumbbell, PartyPopper, Trophy, Map, Calendar, MapPin, Info, Dumbbell, PartyPopper, Trophy, Map, Calendar, MapPin, Info,
MessageCircle, Paperclip, Send MessageCircle, Paperclip, Send
} from 'lucide-react'; } from 'lucide-react';
import { app } from './firebase.js';
import { getAuth, signInWithEmailAndPassword } from 'https://www.gstatic.com/firebasejs/12.1.0/firebase-auth.js';
const auth = getAuth(app);
const INITIAL_RESIDENTS = [ const INITIAL_RESIDENTS = [
{ id: 1, unit: '1º Esq', name: 'Ana Silva', contact: '912 345 678', email: 'ana.silva@email.com', status: 'Pago', pending: 0, role: 'morador' }, { id: 1, unit: '1º Esq', name: 'Ana Silva', contact: '912 345 678', email: 'ana.silva@email.com', status: 'Pago', pending: 0, role: 'morador' },
@@ -1655,6 +1659,8 @@
root.render(<App />); root.render(<App />);
</script> </script>
<!-- Firebase configs moved to top in React Module --> <!-- Firebase configs moved to top in React Module -->
<script type="module" src="script.js"></script>
<script type="module" src="firebase.js"></script>
<script type="module" src="script.js"></script>
</body> </body>
</html> </html>

254
script.js
View File

@@ -1,19 +1,9 @@
const SUPABASE_URL = 'YOUR_SUPABASE_URL'; import { db } from "./firebase.js";
const SUPABASE_KEY = 'YOUR_SUPABASE_KEY'; 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");
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', () => { document.addEventListener('DOMContentLoaded', () => {
checkLogin(); checkLogin();
@@ -22,14 +12,22 @@ document.addEventListener('DOMContentLoaded', () => {
function setupEventListeners() { function setupEventListeners() {
document.getElementById('login-form').addEventListener('submit', handleLogin); const loginForm = document.getElementById('login-form');
if (loginForm) loginForm.addEventListener('submit', handleLogin);
const formMorador = document.getElementById('form-morador');
if (formMorador) formMorador.addEventListener('submit', saveMorador);
document.getElementById('form-morador').addEventListener('submit', saveMorador); const formTransacao = document.getElementById('form-transacao');
document.getElementById('form-transacao').addEventListener('submit', saveTransacao); if (formTransacao) formTransacao.addEventListener('submit', saveTransacao);
document.getElementById('form-ocorrencia').addEventListener('submit', saveOcorrencia);
document.getElementById('form-aviso').addEventListener('submit', saveAviso);
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')) { if (sessionStorage.getItem('condoProUser')) {
renderDashboard(); renderDashboard();
@@ -39,14 +37,21 @@ function setupEventListeners() {
function checkLogin() { function checkLogin() {
const user = sessionStorage.getItem('condoProUser'); const user = sessionStorage.getItem('condoProUser');
const loginSection = document.getElementById('login-section');
const appLayout = document.getElementById('app-layout');
if (user) { if (user) {
document.getElementById('login-section').classList.add('d-none'); if (loginSection) loginSection.classList.add('d-none');
document.getElementById('app-layout').classList.remove('d-none'); if (appLayout) {
document.getElementById('app-layout').classList.add('d-flex'); appLayout.classList.remove('d-none');
appLayout.classList.add('d-flex');
}
} else { } else {
document.getElementById('login-section').classList.remove('d-none'); if (loginSection) loginSection.classList.remove('d-none');
document.getElementById('app-layout').classList.add('d-none'); if (appLayout) {
document.getElementById('app-layout').classList.remove('d-flex'); appLayout.classList.add('d-none');
appLayout.classList.remove('d-flex');
}
} }
} }
@@ -99,39 +104,51 @@ function showToast(message, type = 'primary') {
async function dbSelect(table, orderBy = null) { async function dbSelect(table, orderBy = null) {
if (IS_MOCK) { try {
const data = JSON.parse(localStorage.getItem(`condopro_${table}`)) || []; 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) { if (orderBy) {
data.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); 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 }; return { data, error: null };
} catch (error) {
return { data: null, error };
} }
let query = supabase.from(table).select('*');
if (orderBy) query = query.order(orderBy.col, { ascending: orderBy.asc });
return await query;
} }
async function dbInsert(table, row) { async function dbInsert(table, row) {
row.created_at = new Date().toISOString(); try {
if (!row.id) row.id = Date.now(); row.created_at = new Date().toISOString();
if (!row.id) row.id = Date.now().toString();
if (IS_MOCK) { await set(ref(db, `${table}/${row.id}`), row);
const data = JSON.parse(localStorage.getItem(`condopro_${table}`)) || [];
data.push(row);
localStorage.setItem(`condopro_${table}`, JSON.stringify(data));
return { data: [row], error: null }; return { data: [row], error: null };
} catch (error) {
console.error("Erro no dbInsert:", error);
return { data: null, error };
} }
return await supabase.from(table).insert([row]);
} }
async function dbDelete(table, id) { async function dbDelete(table, id) {
if (IS_MOCK) { try {
let data = JSON.parse(localStorage.getItem(`condopro_${table}`)) || []; await remove(ref(db, `${table}/${id}`));
data = data.filter(item => item.id != id); // Loose comparison for ID
localStorage.setItem(`condopro_${table}`, JSON.stringify(data));
return { error: null }; return { error: null };
} catch (error) {
return { error };
} }
return await supabase.from(table).delete().eq('id', id);
} }
function navigateTo(viewId) { function navigateTo(viewId) {
@@ -267,20 +284,90 @@ function prepareCreateMorador() {
async function saveMorador(e) { async function saveMorador(e) {
e.preventDefault(); 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 }); const fracaoInput = document.getElementById("fracao");
const proprietarioInput = document.getElementById("proprietario");
const contactoInput = document.getElementById("contacto");
if (error) showToast("Erro ao salvar: " + error.message, "danger"); // Fallback para formulário legado caso os IDs sejam diferentes
else { const fracao = fracaoInput ? fracaoInput.value.trim() : document.getElementById("morador-fracao")?.value.trim();
bootstrap.Modal.getInstance(document.getElementById('modalMorador')).hide(); const proprietario = proprietarioInput ? proprietarioInput.value.trim() : document.getElementById("morador-nome")?.value.trim();
renderMoradores(); const contacto = contactoInput ? contactoInput.value.trim() : document.getElementById("morador-contacto")?.value.trim();
showToast("Morador salvo com sucesso!", "success");
// 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 = `
<td><div class="fw-bold">${m.proprietario || 'Sem Nome'}</div></td>
<td>${m.fracao || '-'}</td>
<td>${m.contacto || '-'}</td>
<td>${m.estado || 'Pago'}</td>
<td>
<button class="btn btn-sm btn-outline-danger" onclick="deleteItem('condominos', '${id}')">
Eliminar
</button>
</td>
`;
tbody.appendChild(tr);
});
}
});
} }
async function renderFinanceiro() { async function renderFinanceiro() {
@@ -388,20 +475,9 @@ async function saveOcorrencia(e) {
const fileInput = document.getElementById('ocorrencia-file'); const fileInput = document.getElementById('ocorrencia-file');
let imagem_url = null; let imagem_url = null;
if (IS_MOCK && fileInput.files.length > 0) { if (fileInput.files.length > 0) {
showToast("Upload simulado (Mock Mode)", "info"); showToast("Upload simulado (Firebase Storage não configurado)", "info");
imagem_url = "https://placehold.co/600x400?text=Imagem+Ocorrencia"; 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' }); const { error } = await dbInsert('ocorrencias', { titulo, descricao, imagem_url, status: 'pendente' });
@@ -490,32 +566,24 @@ function exportPDF(tableId, filename) {
doc.save(filename + '.pdf'); doc.save(filename + '.pdf');
showToast("PDF gerado com sucesso!", "success"); showToast("PDF gerado com sucesso!", "success");
} }
import { db } from "./firebase.js"; const guardarBtn = document.getElementById("guardar");
import { collection, addDoc } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-firestore.js"; 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...");
import { db } from "./firebase.js"; try {
import { collection, addDoc } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-firestore.js"; await push(ref(db, "condominios"), {
fracao,
proprietario,
contacto
});
document.getElementById("btnAdicionar").onclick = () => { alert("Guardado com sucesso!");
document.getElementById("formCondominio").style.display = "block"; } catch (e) {
}; alert("Erro: " + e.message);
}
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);
}
};