adicionar objetos ao firebase
This commit is contained in:
252
index.html
252
index.html
@@ -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]);
|
|
||||||
}
|
const newBookingRef = push(ref(db, 'reservas'));
|
||||||
|
await set(newBookingRef, bookingData);
|
||||||
|
|
||||||
showNotification(`Reserva confirmada para ${newBooking.facilityName}`);
|
if (bookingData.cost > 0) {
|
||||||
handleCloseModal();
|
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>
|
||||||
Reference in New Issue
Block a user