239 lines
9.3 KiB
HTML
239 lines
9.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="id">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Laporan — 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">
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js"></script>
|
|
<style>
|
|
.btn-lihat-semua {
|
|
display: flex;
|
|
width: 100%;
|
|
padding: 12px;
|
|
margin-top: 4px;
|
|
background: none;
|
|
border: 1px dashed var(--border-color);
|
|
border-radius: 0 0 12px 12px;
|
|
color: var(--primary-green);
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
font-family: 'Poppins', sans-serif;
|
|
cursor: pointer;
|
|
transition: background 0.2s, border-color 0.2s;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 6px;
|
|
}
|
|
.btn-lihat-semua:hover {
|
|
background: var(--primary-green-light);
|
|
border-color: var(--primary-green);
|
|
}
|
|
tr.hidden-row { display: none; }
|
|
tr.hidden-row.visible { display: table-row; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<script type="module">
|
|
if (localStorage.getItem('isLoggedIn') !== 'true') {
|
|
window.location.href = 'login.html';
|
|
}
|
|
|
|
import { initLayout } from './layout.js';
|
|
import { db, formatRp, formatWaktu, formatTanggal } from './firebase-config.js';
|
|
import { ref, onValue } from "https://www.gstatic.com/firebasejs/12.10.0/firebase-database.js";
|
|
|
|
initLayout('laporan');
|
|
|
|
document.getElementById('content-area').innerHTML = `
|
|
<!-- SUMMARY -->
|
|
<div class="summary-grid" style="margin-bottom:24px;">
|
|
<div class="card">
|
|
<p style="color:var(--text-muted); font-size:13px;">
|
|
<i class="fa-solid fa-arrow-trend-up text-green"></i> TOTAL PEMASUKAN
|
|
</p>
|
|
<h2 id="lap-pemasukan" style="margin-top:6px;">Rp 0</h2>
|
|
</div>
|
|
<div class="card">
|
|
<p style="color:var(--text-muted); font-size:13px;">
|
|
<i class="fa-solid fa-arrow-trend-down text-red"></i> TOTAL PENGELUARAN
|
|
</p>
|
|
<h2 id="lap-pengeluaran" style="margin-top:6px;">Rp 0</h2>
|
|
</div>
|
|
<div class="card" style="background:var(--primary-green); color:white; border:none;">
|
|
<p style="font-size:13px; opacity:0.85;">
|
|
<i class="fa-solid fa-building-columns"></i> SALDO AKHIR
|
|
</p>
|
|
<h2 id="lap-saldo" style="margin-top:6px;">Rp 0</h2>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- EXPORT PDF -->
|
|
<div class="card" style="text-align:center; padding:60px 20px;
|
|
border: 2px dashed var(--primary-green-light); margin-bottom:24px;">
|
|
<i class="fa-solid fa-file-pdf" style="font-size:48px; color:var(--primary-green); margin-bottom:16px;"></i>
|
|
<h3 style="margin-bottom:8px;">Siap untuk diaudit?</h3>
|
|
<p style="color:var(--text-muted); font-size:14px; max-width:400px; margin:0 auto 24px;">
|
|
Unduh salinan resmi laporan dalam format PDF untuk keperluan arsip fisik atau papan pengumuman masjid.
|
|
</p>
|
|
<button class="btn-primary" id="btn-export-pdf" style="width:auto; padding:12px 32px;">
|
|
<i class="fa-solid fa-download"></i> Export PDF
|
|
</button>
|
|
</div>
|
|
|
|
<!-- TABEL RINGKASAN DONASI -->
|
|
<div class="card" style="margin-bottom:24px;">
|
|
<div class="card-header">
|
|
<h3><i class="fa-solid fa-list-check" style="color:var(--primary-green);"></i> Ringkasan Donasi</h3>
|
|
</div>
|
|
<table class="styled-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Waktu</th>
|
|
<th>Nominal</th>
|
|
<th>Confidence</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="lap-table-donasi">
|
|
<tr><td colspan="4" style="text-align:center; color:var(--text-muted); padding:24px;">
|
|
<i class="fa-solid fa-spinner fa-spin"></i> Memuat...
|
|
</td></tr>
|
|
</tbody>
|
|
</table>
|
|
<button class="btn-lihat-semua" id="btn-expand-lap" style="display:none;">
|
|
<i class="fa-solid fa-chevron-down" id="lap-expand-icon"></i>
|
|
<span id="lap-expand-text">Lihat Selengkapnya</span>
|
|
</button>
|
|
</div>
|
|
`;
|
|
|
|
let snapshotDonasi = {};
|
|
let snapshotPengeluaran = {};
|
|
let snapshotSummary = {};
|
|
let isExpanded = false;
|
|
|
|
// ── Firebase: Summary ──
|
|
onValue(ref(db, 'smart_donation_box/summary'), (snap) => {
|
|
snapshotSummary = snap.val() || {};
|
|
const saldo = (snapshotSummary.total_donasi || 0) - (snapshotSummary.total_pengeluaran || 0);
|
|
document.getElementById('lap-pemasukan').innerText = formatRp(snapshotSummary.total_donasi);
|
|
document.getElementById('lap-pengeluaran').innerText = formatRp(snapshotSummary.total_pengeluaran);
|
|
document.getElementById('lap-saldo').innerText = formatRp(saldo);
|
|
});
|
|
|
|
// ── Firebase: Donasi Log ──
|
|
onValue(ref(db, 'smart_donation_box/donasi_log'), (snap) => {
|
|
snapshotDonasi = snap.val() || {};
|
|
|
|
// Filter: buang entry dengan nominal 0
|
|
const keys = Object.keys(snapshotDonasi)
|
|
.reverse()
|
|
.filter(key => (snapshotDonasi[key].nominal || 0) > 0);
|
|
|
|
let html = '';
|
|
|
|
if (keys.length === 0) {
|
|
html = `<tr><td colspan="4" style="text-align:center; color:var(--text-muted); padding:24px;">Belum ada data</td></tr>`;
|
|
document.getElementById('btn-expand-lap').style.display = 'none';
|
|
} else {
|
|
keys.forEach((key, i) => {
|
|
const item = snapshotDonasi[key];
|
|
const conf = ((item.confidence || 0) * 100).toFixed(0);
|
|
const hiddenClass = i >= 5 ? 'hidden-row' : '';
|
|
html += `
|
|
<tr class="${hiddenClass}">
|
|
<td style="color:var(--text-muted);">${formatWaktu(item.timestamp)}</td>
|
|
<td style="font-weight:600;">${formatRp(item.nominal)}</td>
|
|
<td><span style="font-weight:600;">${conf}%</span></td>
|
|
<td><span class="badge-valid">Valid</span></td>
|
|
</tr>
|
|
`;
|
|
});
|
|
|
|
const btnExpand = document.getElementById('btn-expand-lap');
|
|
btnExpand.style.display = keys.length > 5 ? 'flex' : 'none';
|
|
}
|
|
|
|
document.getElementById('lap-table-donasi').innerHTML = html;
|
|
attachExpandHandler();
|
|
});
|
|
|
|
// ── Firebase: Pengeluaran Log ──
|
|
onValue(ref(db, 'smart_donation_box/pengeluaran_log'), (snap) => {
|
|
snapshotPengeluaran = snap.val() || {};
|
|
});
|
|
|
|
function attachExpandHandler() {
|
|
const btn = document.getElementById('btn-expand-lap');
|
|
if (!btn) return;
|
|
btn.onclick = () => {
|
|
isExpanded = !isExpanded;
|
|
document.querySelectorAll('#lap-table-donasi tr.hidden-row').forEach(row => {
|
|
row.classList.toggle('visible', isExpanded);
|
|
});
|
|
document.getElementById('lap-expand-icon').className =
|
|
isExpanded ? 'fa-solid fa-chevron-up' : 'fa-solid fa-chevron-down';
|
|
document.getElementById('lap-expand-text').textContent =
|
|
isExpanded ? 'Sembunyikan' : 'Lihat Selengkapnya';
|
|
};
|
|
}
|
|
|
|
// ── Export PDF ──
|
|
document.getElementById('btn-export-pdf').addEventListener('click', () => {
|
|
const { jsPDF } = window.jspdf;
|
|
const doc = new jsPDF();
|
|
|
|
doc.setFontSize(18);
|
|
doc.setTextColor(16, 185, 129);
|
|
doc.text('LAPORAN KAS SMART DONATION BOX', 14, 20);
|
|
|
|
doc.setFontSize(10);
|
|
doc.setTextColor(100, 116, 139);
|
|
doc.text(`Dicetak: ${new Date().toLocaleDateString('id-ID', {
|
|
weekday:'long', year:'numeric', month:'long', day:'numeric'
|
|
})}`, 14, 28);
|
|
|
|
doc.setFontSize(12);
|
|
doc.setTextColor(30, 41, 59);
|
|
doc.text('RINGKASAN KEUANGAN', 14, 42);
|
|
|
|
const saldo = (snapshotSummary.total_donasi || 0) - (snapshotSummary.total_pengeluaran || 0);
|
|
|
|
doc.autoTable({
|
|
startY: 46,
|
|
head: [['Keterangan', 'Jumlah']],
|
|
body: [
|
|
['Total Pemasukan', formatRp(snapshotSummary.total_donasi)],
|
|
['Total Pengeluaran', formatRp(snapshotSummary.total_pengeluaran)],
|
|
['Saldo Akhir', formatRp(saldo)],
|
|
],
|
|
headStyles: { fillColor: [16, 185, 129] },
|
|
columnStyles: { 1: { halign: 'right' } },
|
|
margin: { left: 14, right: 14 }
|
|
});
|
|
|
|
const kelKeys = Object.keys(snapshotPengeluaran).reverse();
|
|
if (kelKeys.length > 0) {
|
|
doc.text('LOG PENGELUARAN', 14, doc.lastAutoTable.finalY + 14);
|
|
doc.autoTable({
|
|
startY: doc.lastAutoTable.finalY + 18,
|
|
head: [['Tanggal', 'Keterangan', 'Nominal']],
|
|
body: kelKeys.map(k => {
|
|
const item = snapshotPengeluaran[k];
|
|
return [formatTanggal(item.timestamp), item.keterangan, formatRp(item.nominal)];
|
|
}),
|
|
headStyles: { fillColor: [239, 68, 68] },
|
|
margin: { left: 14, right: 14 }
|
|
});
|
|
}
|
|
|
|
doc.save(`Laporan_SmartDonationBox_${new Date().toISOString().slice(0,10)}.pdf`);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |