TKK_E32230947/web/laporan.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>