adicionar condóminos
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"liveServer.settings.port": 5503
|
||||
"liveServer.settings.port": 5504
|
||||
}
|
||||
20
firebase.js
20
firebase.js
@@ -1,16 +1,18 @@
|
||||
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 = {
|
||||
apiKey: "SUA_API_KEY",
|
||||
authDomain: "SEU_PROJETO.firebaseapp.com",
|
||||
projectId: "SEU_PROJECT_ID",
|
||||
storageBucket: "SEU_PROJETO.appspot.com",
|
||||
messagingSenderId: "SEU_ID",
|
||||
appId: "SEU_APP_ID"
|
||||
apiKey: "AQUI_TUA_API_KEY",
|
||||
authDomain: "AQUI.firebaseapp.com",
|
||||
databaseURL: "https://condomaster-pro-ed9af-default-rtdb.europe-west1.firebasedatabase.app",
|
||||
projectId: "condomaster-pro-ed9af",
|
||||
storageBucket: "condomaster-pro-ed9af.appspot.com",
|
||||
messagingSenderId: "AQUI",
|
||||
appId: "AQUI"
|
||||
};
|
||||
|
||||
const app = initializeApp(firebaseConfig);
|
||||
const db = getFirestore(app);
|
||||
const db = getDatabase(app);
|
||||
|
||||
export { app, db };
|
||||
|
||||
export { db };
|
||||
@@ -98,6 +98,10 @@
|
||||
Dumbbell, PartyPopper, Trophy, Map, Calendar, MapPin, Info,
|
||||
MessageCircle, Paperclip, Send
|
||||
} 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 = [
|
||||
{ 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 />);
|
||||
</script>
|
||||
<!-- 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>
|
||||
</html>
|
||||
254
script.js
254
script.js
@@ -1,19 +1,9 @@
|
||||
|
||||
|
||||
const SUPABASE_URL = 'YOUR_SUPABASE_URL';
|
||||
const SUPABASE_KEY = 'YOUR_SUPABASE_KEY';
|
||||
import { db } from "./firebase.js";
|
||||
import { ref, get, set, remove, push, onValue } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-database.js";
|
||||
|
||||
|
||||
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");
|
||||
}
|
||||
console.log("Integração com Firebase Database Iniciada");
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
checkLogin();
|
||||
@@ -22,14 +12,22 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
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);
|
||||
document.getElementById('form-transacao').addEventListener('submit', saveTransacao);
|
||||
document.getElementById('form-ocorrencia').addEventListener('submit', saveOcorrencia);
|
||||
document.getElementById('form-aviso').addEventListener('submit', saveAviso);
|
||||
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();
|
||||
@@ -39,14 +37,21 @@ function setupEventListeners() {
|
||||
|
||||
function checkLogin() {
|
||||
const user = sessionStorage.getItem('condoProUser');
|
||||
const loginSection = document.getElementById('login-section');
|
||||
const appLayout = document.getElementById('app-layout');
|
||||
|
||||
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');
|
||||
if (loginSection) loginSection.classList.add('d-none');
|
||||
if (appLayout) {
|
||||
appLayout.classList.remove('d-none');
|
||||
appLayout.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');
|
||||
if (loginSection) loginSection.classList.remove('d-none');
|
||||
if (appLayout) {
|
||||
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) {
|
||||
if (IS_MOCK) {
|
||||
const data = JSON.parse(localStorage.getItem(`condopro_${table}`)) || [];
|
||||
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) => 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 };
|
||||
} 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) {
|
||||
row.created_at = new Date().toISOString();
|
||||
if (!row.id) row.id = Date.now();
|
||||
try {
|
||||
row.created_at = new Date().toISOString();
|
||||
if (!row.id) row.id = Date.now().toString();
|
||||
|
||||
if (IS_MOCK) {
|
||||
const data = JSON.parse(localStorage.getItem(`condopro_${table}`)) || [];
|
||||
data.push(row);
|
||||
localStorage.setItem(`condopro_${table}`, JSON.stringify(data));
|
||||
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 };
|
||||
}
|
||||
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));
|
||||
try {
|
||||
await remove(ref(db, `${table}/${id}`));
|
||||
return { error: null };
|
||||
} catch (error) {
|
||||
return { error };
|
||||
}
|
||||
return await supabase.from(table).delete().eq('id', id);
|
||||
}
|
||||
|
||||
function navigateTo(viewId) {
|
||||
@@ -267,20 +284,90 @@ function prepareCreateMorador() {
|
||||
|
||||
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 });
|
||||
const fracaoInput = document.getElementById("fracao");
|
||||
const proprietarioInput = document.getElementById("proprietario");
|
||||
const contactoInput = document.getElementById("contacto");
|
||||
|
||||
if (error) showToast("Erro ao salvar: " + error.message, "danger");
|
||||
else {
|
||||
bootstrap.Modal.getInstance(document.getElementById('modalMorador')).hide();
|
||||
renderMoradores();
|
||||
showToast("Morador salvo com sucesso!", "success");
|
||||
// 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 = `
|
||||
<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() {
|
||||
@@ -388,20 +475,9 @@ async function saveOcorrencia(e) {
|
||||
const fileInput = document.getElementById('ocorrencia-file');
|
||||
let imagem_url = null;
|
||||
|
||||
if (IS_MOCK && fileInput.files.length > 0) {
|
||||
showToast("Upload simulado (Mock Mode)", "info");
|
||||
if (fileInput.files.length > 0) {
|
||||
showToast("Upload simulado (Firebase Storage não configurado)", "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' });
|
||||
@@ -490,32 +566,24 @@ function exportPDF(tableId, filename) {
|
||||
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";
|
||||
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...");
|
||||
|
||||
import { db } from "./firebase.js";
|
||||
import { collection, addDoc } from "https://www.gstatic.com/firebasejs/12.1.0/firebase-firestore.js";
|
||||
try {
|
||||
await push(ref(db, "condominios"), {
|
||||
fracao,
|
||||
proprietario,
|
||||
contacto
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
alert("Guardado com sucesso!");
|
||||
} catch (e) {
|
||||
alert("Erro: " + e.message);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user