162 lines
7.0 KiB
HTML
162 lines
7.0 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Pengeluaran — Smart Donation Box</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
|
<link rel="stylesheet" href="style.css">
|
|
</head>
|
|
<body>
|
|
|
|
<script type="module">
|
|
if (localStorage.getItem('isLoggedIn') !== 'true') {
|
|
window.location.href = 'login.html';
|
|
}
|
|
|
|
import { initLayout } from './layout.js';
|
|
import { db, formatRp, formatTanggal } from './firebase-config.js';
|
|
import { ref, onValue, push, get, update } from "https://www.gstatic.com/firebasejs/12.10.0/firebase-database.js";
|
|
|
|
initLayout('pengeluaran');
|
|
|
|
document.getElementById('content-area').innerHTML = `
|
|
<div class="grid-2">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h3 style="color:var(--primary-green);"><i class="fa-solid fa-circle-plus"></i> Input Pengeluaran Baru</h3>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Nominal (Rp)</label>
|
|
<input type="number" id="input-nominal-keluar" placeholder="Misal: 50000" min="0">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Keterangan</label>
|
|
<input type="text" id="input-ket-keluar" placeholder="Misal: Pembelian alat kebersihan">
|
|
</div>
|
|
<button class="btn-primary" id="btn-simpan-pengeluaran">
|
|
<i class="fa-solid fa-floppy-disk"></i> Simpan Pengeluaran
|
|
</button>
|
|
<p id="msg-pengeluaran" style="margin-top:12px; font-size:13px; text-align:center; min-height:20px;"></p>
|
|
</div>
|
|
|
|
<div style="display:flex; flex-direction:column; gap:24px;">
|
|
<div class="card" style="flex:1;">
|
|
<div class="card-header">
|
|
<h3><i class="fa-solid fa-clock-rotate-left" style="color:var(--primary-green);"></i> Riwayat Pengeluaran</h3>
|
|
</div>
|
|
<table class="styled-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Tanggal</th>
|
|
<th>Keterangan</th>
|
|
<th>Nominal</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="table-riwayat-pengeluaran">
|
|
<tr><td colspan="3" style="text-align:center; color:var(--text-muted); padding:24px;">
|
|
<i class="fa-solid fa-spinner fa-spin"></i> Memuat...
|
|
</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="summary-grid-2" style="margin-bottom:0;">
|
|
<div class="card bg-green-light" style="border:none;">
|
|
<p style="font-size:13px; color:var(--primary-green);">Total Pengeluaran</p>
|
|
<h2 class="text-green" id="pengeluaran-total" style="margin-top:4px;">Rp 0</h2>
|
|
</div>
|
|
<div class="card">
|
|
<p style="font-size:13px; color:var(--text-muted);">Sisa Saldo Kas</p>
|
|
<h2 id="pengeluaran-saldo" style="margin-top:4px;">Rp 0</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
const summaryRef = ref(db, 'smart_donation_box/summary');
|
|
|
|
onValue(summaryRef, (snap) => {
|
|
const d = snap.val() || {};
|
|
const saldo = (d.total_donasi || 0) - (d.total_pengeluaran || 0);
|
|
document.getElementById('pengeluaran-total').innerText = formatRp(d.total_pengeluaran);
|
|
document.getElementById('pengeluaran-saldo').innerText = formatRp(saldo);
|
|
});
|
|
|
|
onValue(ref(db, 'smart_donation_box/pengeluaran_log'), (snap) => {
|
|
const data = snap.val() || {};
|
|
|
|
// Filter: buang entry dengan nominal 0 atau keterangan tidak valid
|
|
const keys = Object.keys(data)
|
|
.reverse()
|
|
.filter(key => (data[key].nominal || 0) > 0);
|
|
|
|
let html = '';
|
|
|
|
if (keys.length === 0) {
|
|
html = `<tr><td colspan="3" style="text-align:center; color:var(--text-muted); padding:24px;">
|
|
Belum ada pengeluaran
|
|
</td></tr>`;
|
|
} else {
|
|
keys.forEach(key => {
|
|
const item = data[key];
|
|
html += `
|
|
<tr>
|
|
<td style="color:var(--text-muted);">${formatTanggal(item.timestamp)}</td>
|
|
<td style="font-weight:500;">${item.keterangan}</td>
|
|
<td style="font-weight:600; color:var(--danger-red);">${formatRp(item.nominal)}</td>
|
|
</tr>
|
|
`;
|
|
});
|
|
}
|
|
document.getElementById('table-riwayat-pengeluaran').innerHTML = html;
|
|
});
|
|
|
|
document.getElementById('btn-simpan-pengeluaran').addEventListener('click', async () => {
|
|
const nominal = Number(document.getElementById('input-nominal-keluar').value);
|
|
const keterangan = document.getElementById('input-ket-keluar').value.trim();
|
|
const msg = document.getElementById('msg-pengeluaran');
|
|
|
|
if (!nominal || nominal <= 0) return showMsg(msg, '⚠️ Masukkan nominal yang valid!', 'orange');
|
|
if (!keterangan) return showMsg(msg, '⚠️ Keterangan tidak boleh kosong!', 'orange');
|
|
|
|
const btn = document.getElementById('btn-simpan-pengeluaran');
|
|
btn.disabled = true;
|
|
btn.innerHTML = '<i class="fa-solid fa-spinner fa-spin"></i> Menyimpan...';
|
|
|
|
try {
|
|
const snap = await get(summaryRef);
|
|
const current = snap.val() || {};
|
|
const newTotal = (current.total_pengeluaran || 0) + nominal;
|
|
const newSaldo = (current.total_donasi || 0) - newTotal;
|
|
|
|
await push(ref(db, 'smart_donation_box/pengeluaran_log'), {
|
|
nominal, keterangan, timestamp: Date.now()
|
|
});
|
|
await update(summaryRef, {
|
|
total_pengeluaran: newTotal,
|
|
saldo: newSaldo
|
|
});
|
|
|
|
document.getElementById('input-nominal-keluar').value = '';
|
|
document.getElementById('input-ket-keluar').value = '';
|
|
showMsg(msg, '✅ Pengeluaran berhasil disimpan!', 'var(--primary-green)');
|
|
} catch (e) {
|
|
console.error(e);
|
|
showMsg(msg, '❌ Gagal menyimpan. Coba lagi.', 'var(--danger-red)');
|
|
} finally {
|
|
btn.disabled = false;
|
|
btn.innerHTML = '<i class="fa-solid fa-floppy-disk"></i> Simpan Pengeluaran';
|
|
}
|
|
});
|
|
|
|
function showMsg(el, text, color) {
|
|
el.innerText = text;
|
|
el.style.color = color;
|
|
setTimeout(() => el.innerText = '', 3000);
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |