adicionar objetos ao firebase

This commit is contained in:
2026-04-23 16:11:09 +01:00
parent c251549f63
commit 255c1a39f4

View File

@@ -100,8 +100,10 @@
} from 'lucide-react'; } from 'lucide-react';
import { app } from './firebase.js'; import { app } from './firebase.js';
import { getAuth, signInWithEmailAndPassword } from 'https://www.gstatic.com/firebasejs/12.1.0/firebase-auth.js'; import { getAuth, signInWithEmailAndPassword } from 'https://www.gstatic.com/firebasejs/12.1.0/firebase-auth.js';
import { getDatabase, ref, push, set, onValue, remove } from 'https://www.gstatic.com/firebasejs/12.1.0/firebase-database.js';
const auth = getAuth(app); const auth = getAuth(app);
const db = getDatabase(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' },
@@ -383,10 +385,36 @@
} }
}; };
const [residents, setResidents] = useState(INITIAL_RESIDENTS); const [residents, setResidents] = useState([]);
const [finances, setFinances] = useState(INITIAL_FINANCES); const [finances, setFinances] = useState([]);
const [issues, setIssues] = useState(INITIAL_ISSUES); const [issues, setIssues] = useState([]);
const [bookings, setBookings] = useState(INITIAL_BOOKINGS); const [bookings, setBookings] = useState([]);
const [invoices, setInvoices] = useState([]);
useEffect(() => {
const loadData = (path, setter, sortFunc = null) => {
return onValue(ref(db, path), (snapshot) => {
const data = snapshot.val();
if (data) {
let parsed = Object.entries(data).map(([id, val]) => ({ id, ...val }));
if (sortFunc) parsed = parsed.sort(sortFunc);
setter(parsed);
} else {
setter([]);
}
}, (error) => console.error(`Erro ao carregar ${path}:`, error));
};
const unsubResidents = loadData('condominos', setResidents);
const unsubFinances = loadData('financas', setFinances, (a,b) => new Date(b.date) - new Date(a.date));
const unsubIssues = loadData('manutencao', setIssues, (a,b) => new Date(b.date) - new Date(a.date));
const unsubBookings = loadData('reservas', setBookings, (a,b) => new Date(a.date) - new Date(b.date));
const unsubInvoices = loadData('faturacao', setInvoices, (a,b) => new Date(b.date) - new Date(a.date));
return () => {
unsubResidents(); unsubFinances(); unsubIssues(); unsubBookings(); unsubInvoices();
};
}, []);
const [notificationsList, setNotificationsList] = useState(INITIAL_NOTIFICATIONS); const [notificationsList, setNotificationsList] = useState(INITIAL_NOTIFICATIONS);
const [isNotificationsOpen, setNotificationsOpen] = useState(false); const [isNotificationsOpen, setNotificationsOpen] = useState(false);
@@ -497,78 +525,174 @@
}); });
}; };
const handleToggleRole = (id) => { const handleToggleRole = async (id) => {
setResidents(residents.map(r => r.id === id ? { ...r, role: r.role === 'admin' ? 'morador' : 'admin' } : r)); try {
showNotification('Permissões de utilizador atualizadas', 'success'); const resident = residents.find(r => r.id === id);
}; if (resident) {
const newRole = resident.role === 'admin' ? 'morador' : 'admin';
const handleSaveResident = (e) => { const residentRef = ref(db, `condominos/${id}`);
e.preventDefault(); await set(residentRef, { ...resident, role: newRole });
if (editingItem) { showNotification('Permissões de utilizador atualizadas', 'success');
setResidents(residents.map(r => r.id === editingItem.id ? { ...formData, id: r.id } : r)); }
showNotification(`Condómino ${formData.name} atualizado`); } catch (error) {
} else { console.error("Erro ao atualizar permissão:", error);
setResidents([...residents, { ...formData, id: Date.now(), pending: Number(formData.pending) }]); showNotification("Erro ao atualizar permissão.", "error");
showNotification(`Novo condómino ${formData.name} adicionado`);
} }
handleCloseModal();
}; };
const handleDeleteResident = (id) => { const handleSaveResident = async (e) => {
e.preventDefault();
try {
if (editingItem) {
const residentRef = ref(db, `condominos/${editingItem.id}`);
await set(residentRef, {
unit: formData.unit || '',
name: formData.name || '',
contact: formData.contact || '',
email: formData.email || '',
status: formData.status || 'Pago',
pending: Number(formData.pending) || 0,
role: formData.role || 'morador'
});
showNotification(`Condómino ${formData.name} atualizado`);
} else {
const residentsListRef = ref(db, 'condominos');
const newResidentRef = push(residentsListRef);
await set(newResidentRef, {
unit: formData.unit || '',
name: formData.name || '',
contact: formData.contact || '',
email: formData.email || '',
status: formData.status || 'Pago',
pending: Number(formData.pending) || 0,
role: formData.role || 'morador'
});
showNotification(`Novo condómino ${formData.name} adicionado`);
}
handleCloseModal();
} catch (error) {
console.error("Erro ao guardar no Firebase:", error);
showNotification("Erro ao guardar os dados.", "error");
}
};
const handleDeleteResident = async (id) => {
if (window.confirm('Tem a certeza que deseja eliminar este condómino?')) { if (window.confirm('Tem a certeza que deseja eliminar este condómino?')) {
setResidents(residents.filter(r => r.id !== id)); try {
showNotification('Condómino removido', 'error'); const residentRef = ref(db, `condominos/${id}`);
await remove(residentRef);
showNotification('Condómino removido', 'error');
} catch (error) {
console.error("Erro ao eliminar no Firebase:", error);
showNotification("Erro ao eliminar.", "error");
}
} }
}; };
const handleSaveFinance = (e) => { const handleSaveFinance = async (e) => {
e.preventDefault(); e.preventDefault();
const amount = Number(formData.amount); if (!formData.amount || !formData.category || !formData.date) {
const newTransaction = { ...formData, id: Date.now(), amount }; showNotification("Preencha todos os campos obrigatórios.", "error");
setFinances([newTransaction, ...finances]); return;
showNotification(`Movimento de ${amount}€ registado`); }
handleCloseModal(); try {
const amount = Number(formData.amount);
const newFinanceRef = push(ref(db, 'financas'));
await set(newFinanceRef, { ...formData, amount });
showNotification(`Movimento de ${amount}€ registado`);
handleCloseModal();
} catch (error) {
console.error("Erro ao guardar finanças:", error);
showNotification("Erro ao guardar movimento.", "error");
}
}; };
const handleSaveIssue = (e) => { const handleSaveIssue = async (e) => {
e.preventDefault(); e.preventDefault();
const newIssue = { ...formData, id: Date.now() }; if (!formData.title || !formData.location) {
setIssues([newIssue, ...issues]); showNotification("Preencha todos os campos obrigatórios.", "error");
showNotification('Nova ocorrência reportada', 'warning'); return;
handleCloseModal(); }
try {
const newIssueRef = push(ref(db, 'manutencao'));
await set(newIssueRef, { ...formData });
showNotification('Nova ocorrência reportada', 'warning');
handleCloseModal();
} catch (error) {
console.error("Erro ao reportar ocorrência:", error);
showNotification("Erro ao reportar ocorrência.", "error");
}
}; };
const handleResolveIssue = (id) => { const handleResolveIssue = async (id) => {
setIssues(issues.map(i => i.id === id ? { ...i, status: 'Resolvido' } : i)); try {
showNotification('Ocorrência resolvida com sucesso'); const issue = issues.find(i => i.id === id);
if (issue) {
await set(ref(db, `manutencao/${id}`), { ...issue, status: 'Resolvido' });
showNotification('Ocorrência resolvida com sucesso');
}
} catch (error) {
console.error("Erro ao resolver ocorrência:", error);
showNotification("Erro ao resolver ocorrência.", "error");
}
}; };
const handleSaveBooking = (e) => { const handleSaveBooking = async (e) => {
e.preventDefault(); e.preventDefault();
const facilityNames = { 'gym': 'Ginásio', 'hall': 'Salão de Festas', 'park': 'Parque de Jogos' }; if (!formData.resident || !formData.date || !formData.time) {
const newBooking = { showNotification("Preencha todos os campos obrigatórios.", "error");
...formData, return;
id: Date.now(), }
facilityName: facilityNames[formData.facility], try {
status: 'Confirmado' const facilityNames = { 'gym': 'Ginásio', 'hall': 'Salão de Festas', 'park': 'Parque de Jogos' };
}; const bookingData = {
setBookings([newBooking, ...bookings]); ...formData,
facilityName: facilityNames[formData.facility],
if (newBooking.cost > 0) { status: 'Confirmado'
const newIncome = {
id: Date.now() + 1,
type: 'income',
category: `Reserva: ${newBooking.facilityName}`,
date: newBooking.date,
amount: newBooking.cost,
desc: `Reserva por ${newBooking.resident}`
}; };
setFinances(prev => [newIncome, ...prev]);
}
showNotification(`Reserva confirmada para ${newBooking.facilityName}`); const newBookingRef = push(ref(db, 'reservas'));
handleCloseModal(); await set(newBookingRef, bookingData);
}
if (bookingData.cost > 0) {
const newIncomeRef = push(ref(db, 'financas'));
await set(newIncomeRef, {
type: 'income',
category: `Reserva: ${bookingData.facilityName}`,
date: bookingData.date,
amount: bookingData.cost,
desc: `Reserva por ${bookingData.resident}`
});
}
showNotification(`Reserva confirmada para ${bookingData.facilityName}`);
handleCloseModal();
} catch (error) {
console.error("Erro ao criar reserva:", error);
showNotification("Erro ao criar reserva.", "error");
}
};
const handleGenerateInvoice = async (resident) => {
if (resident.pending <= 0) {
showNotification(`Não há dívidas para a fração ${resident.unit}`, 'warning');
return;
}
try {
const newInvoiceRef = push(ref(db, 'faturacao'));
await set(newInvoiceRef, {
residentId: resident.id,
unit: resident.unit,
name: resident.name,
amount: Number(resident.pending),
date: new Date().toISOString().split('T')[0],
status: 'Emitida'
});
showNotification(`Fatura instantânea gerada para a fração ${resident.unit}`, 'success');
} catch (error) {
console.error("Erro ao faturar:", error);
showNotification("Erro ao gerar fatura.", "error");
}
};
const DashboardView = () => ( const DashboardView = () => (
<div className="space-y-6 animate-fade-in"> <div className="space-y-6 animate-fade-in">
@@ -1300,12 +1424,7 @@
))} ))}
</tbody> </tbody>
</table> </table>
<div id="formCondominio" style={{display: 'none'}}>
<input id="fracao" placeholder="Fração" />
<input id="proprietario" placeholder="Proprietário" />
<input id="contacto" placeholder="Contacto" />
<button id="guardar">Guardar</button>
</div>
</div> </div>
</div> </div>
)} )}
@@ -1349,7 +1468,7 @@
Notificar Notificar
</button> </button>
<button <button
onClick={() => showNotification(`Fatura instantânea gerada para a fração ${resident.unit}`, 'success')} onClick={() => handleGenerateInvoice(resident)}
className="ml-2 px-3 py-1.5 rounded-lg text-xs font-bold transition-colors shadow-sm bg-slate-800 text-white hover:bg-slate-900 dark:bg-slate-700 dark:hover:bg-slate-600" className="ml-2 px-3 py-1.5 rounded-lg text-xs font-bold transition-colors shadow-sm bg-slate-800 text-white hover:bg-slate-900 dark:bg-slate-700 dark:hover:bg-slate-600"
> >
Faturar na Hora Faturar na Hora
@@ -1659,8 +1778,5 @@
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>