Files
SIG_UAS_Pengentasan_Kemiskinan/index.html
T

1252 lines
70 KiB
HTML

<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sistem Manajemen GIS - Modern Dashboard</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
body { height: 100vh; margin: 0; display: flex; flex-direction: column; font-family: 'Segoe UI', system-ui, sans-serif; background-color: #f4f6f9; }
.navbar { background: linear-gradient(135deg, #1a365d 0%, #2a4365 100%); z-index: 1000; box-shadow: 0 2px 10px rgba(0,0,0,0.15); }
#mainContainer { flex: 1; display: flex; overflow: hidden; position: relative; }
#sidebar { width: 420px; background: white; box-shadow: 3px 0 15px rgba(0,0,0,0.05); display: flex; flex-direction: column; z-index: 999; transition: all 0.3s ease; overflow-y: auto; }
#map { flex: 1; height: 100%; z-index: 1; }
.nav-tabs .nav-link { border: none; color: #718096; padding: 12px 20px; font-weight: 500; border-bottom: 3px solid transparent; }
.nav-tabs .nav-link.active { color: #2b6cb0; border-bottom-color: #2b6cb0; background: transparent; }
.card-stats { border-radius: 12px; border: none; box-shadow: 0 4px 6px rgba(0,0,0,0.02); transition: transform 0.2s; }
.card-stats:hover { transform: translateY(-3px); }
.table-responsive { max-height: 280px; overflow-y: auto; }
.table th { font-weight: 600; color: #4a5568; background-color: #f7fafc; border-top: none; }
.btn-xs { padding: 2px 6px; font-size: 0.75rem; border-radius: 4px; }
#loginScreen { position: fixed; top:0; left:0; width:100vw; height:100vh; background: rgba(26, 54, 93, 0.4); backdrop-filter: blur(8px); z-index: 9999; display: flex; align-items: center; justify-content: center; }
.login-box { background: white; padding: 40px; border-radius: 16px; width: 100%; max-width: 400px; box-shadow: 0 10px 25px rgba(0,0,0,0.1); border: 1px solid rgba(0,0,0,0.05); }
.selected-masjid-marker {
background-color: #e53e3e; color: white; border-radius: 50%; width: 34px; height: 34px;
display: flex; align-items: center; justify-content: center; box-shadow: 0 0 0 0 rgba(229, 62, 62, 0.7);
animation: pulse-red-marker 1.2s infinite cubic-bezier(0.66, 0, 0, 1); border: 2px solid white;
}
@keyframes pulse-red-marker {
to { box-shadow: 0 0 0 14px rgba(229, 62, 62, 0); }
}
.small-text-muted { font-size: 0.75rem; color: #a0aec0; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: #f1f1f1; }
::-webkit-scrollbar-thumb { background: #cbd5e0; border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: #a0aec0; }
.mode-tambah-aktif {
cursor: crosshair !important;
}
</style>
</head>
<body>
<div id="loginScreen" style="display: none;">
<div class="login-box">
<div class="text-center mb-4">
<div class="bg-primary text-white rounded-circle d-inline-flex align-items-center justify-content-center mb-3" style="width: 60px; height: 60px;">
<i class="fas fa-map-marked-alt fa-2x"></i>
</div>
<h4 class="fw-bold text-dark">Sistem Pemetaan GIS</h4>
<p class="text-muted small">Silakan masuk dengan akun anda</p>
</div>
<form id="loginForm">
<div class="mb-3">
<label class="form-label small fw-semibold text-secondary">Username</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0"><i class="fas fa-user text-muted"></i></span>
<input type="text" id="loginUsername" class="form-control bg-light border-start-0" placeholder="Masukkan username" required>
</div>
</div>
<div class="mb-4">
<label class="form-label small fw-semibold text-secondary">Password</label>
<div class="input-group">
<span class="input-group-text bg-light border-end-0"><i class="fas fa-lock text-muted"></i></span>
<input type="password" id="loginPassword" class="form-control bg-light border-start-0" placeholder="••••••••" required>
</div>
</div>
<button type="submit" class="btn btn-primary w-100 py-2 fw-semibold">Masuk Aplikasi <i class="fas fa-sign-in-alt ms-1"></i></button>
</form>
</div>
</div>
<nav class="navbar navbar-expand-lg navbar-dark px-3 py-2">
<div class="container-fluid">
<a class="navbar-brand fw-bold d-flex align-items-center" href="#">
<i class="fas fa-globe-asia text-info me-2 fa-lg"></i>
<div>
<span class="d-block lh-1 text-white">GIS-PEMBERDAYAAN</span>
<span class="small-text-muted" style="font-size: 10px; letter-spacing: 1px;">KOTA PONTIANAK</span>
</div>
</a>
<div class="d-flex align-items-center gap-3">
<span id="userBadge" class="badge bg-light text-primary py-2 px-3 fw-semibold shadow-sm" style="font-size:12px;">Role: -</span>
<button class="btn btn-outline-light btn-sm fw-semibold px-3" onclick="handleLogout()"><i class="fas fa-power-off me-1"></i> Keluar</button>
</div>
</div>
</nav>
<div id="mainContainer">
<div id="sidebar" class="p-3">
<div id="navTabsContainer" class="mb-3">
<ul class="nav nav-tabs nav-fill border-bottom w-100">
<li class="nav-item">
<button class="nav-link tab-btn active w-100" id="btnTabOrang" onclick="switchTab('tabOrang')"><i class="fas fa-user-friends me-1"></i> Warga</button>
</li>
<li class="nav-item">
<button class="nav-link tab-btn w-100" id="btnTabMasjid" onclick="switchTab('tabMasjid')"><i class="fas fa-mosque me-1"></i> Masjid</button>
</li>
<li class="nav-item">
<button class="nav-link tab-btn w-100 d-none" id="btnTabAkun" onclick="switchTab('tabAkun')"><i class="fas fa-user-cog me-1"></i> Akun</button>
</li>
</ul>
</div>
<div id="dynamicWorkspace">
<div id="tabOrang" class="dynamic-section">
<div class="mb-3 d-flex gap-2">
<input type="text" id="searchOrang" class="form-control" placeholder="Cari warga...">
<button type="button" class="btn btn-success text-nowrap" onclick="aktifkanModeTambah('orang')">
<i class="fas fa-user-plus me-1"></i> Tambah Warga
</button>
</div>
<div class="table-responsive border rounded bg-white mb-3 shadow-sm">
<table class="table table-hover table-sm align-middle mb-0" style="font-size: 12px;">
<thead>
<tr>
<th>Nama Warga</th>
<th>No KK</th>
<th>Status</th>
<th class="text-end">Aksi</th>
</tr>
</thead>
<tbody id="tableOrangBody"></tbody>
</table>
</div>
<div class="card p-3 border shadow-sm" style="background:#f8fafc; border-radius:12px;">
<h6 class="fw-bold text-dark mb-2 small"><i class="fas fa-edit me-1 text-primary"></i> Form Kelola Warga Berkebutuhan</h6>
<form id="orangForm">
<input type="hidden" id="orangId">
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Nama Lengkap</label>
<input type="text" id="orangNama" class="form-control form-control-sm" required>
</div>
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Nomor KK</label>
<input type="text" id="orangKk" class="form-control form-control-sm" required>
</div>
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Alamat Rumah</label>
<textarea id="orangAlamat" class="form-control form-control-sm" rows="2" required placeholder="Klik peta/geser marker untuk memicu otomatis alamat..."></textarea>
</div>
<div class="row g-2 mb-2">
<div class="col-6">
<label class="form-label mb-0 small text-muted">Tanggal Lahir</label>
<input type="date" id="orangTglLahir" class="form-control form-control-sm" required>
</div>
<div class="col-6">
<label class="form-label mb-0 small text-muted">No HP / WhatsApp</label>
<input type="text" id="orangHp" class="form-control form-control-sm" required>
</div>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label mb-0 small text-muted">Latitude</label>
<input type="text" id="orangLat" class="form-control form-control-sm" readonly required placeholder="Klik Peta">
</div>
<div class="col-6">
<label class="form-label mb-0 small text-muted">Longitude</label>
<input type="text" id="orangLng" class="form-control form-control-sm" readonly required placeholder="Klik Peta">
</div>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary btn-sm w-100 fw-semibold">Simpan Data</button>
<button type="button" class="btn btn-dark btn-sm fw-semibold" onclick="batalAksiModeForm('orang')"><i class="fas fa-times me-1"></i> Batal</button>
</div>
</form>
</div>
</div>
<div id="tabMasjid" class="dynamic-section d-none">
<div class="mb-3 d-flex gap-2">
<input type="text" id="searchMasjid" class="form-control" placeholder="Cari masjid...">
<button type="button" class="btn btn-primary text-nowrap" onclick="aktifkanModeTambah('masjid')">
<i class="fas fa-plus-circle me-1"></i> Tambah Masjid
</button>
</div>
<div class="table-responsive border rounded bg-white mb-3 shadow-sm">
<table class="table table-hover table-sm align-middle mb-0" style="font-size: 12px;">
<thead>
<tr>
<th>Nama Masjid</th>
<th>Radius</th>
<th class="text-center">Diampu</th>
<th class="text-end">Aksi</th>
</tr>
</thead>
<tbody id="tableMasjidBody"></tbody>
</table>
</div>
<div class="card p-3 border shadow-sm" style="background:#f8fafc; border-radius:12px;">
<h6 class="fw-bold text-dark mb-2 small"><i class="fas fa-edit me-1 text-primary"></i> Form Kelola Titik Masjid</h6>
<form id="masjidForm">
<input type="hidden" id="masjidId">
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Nama Masjid</label>
<input type="text" id="masjidNama" class="form-control form-control-sm" required>
</div>
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Alamat Lengkap</label>
<textarea id="masjidAlamat" class="form-control form-control-sm" rows="2" required placeholder="Klik peta/geser marker untuk memicu otomatis alamat..."></textarea>
</div>
<div class="row g-2 mb-2">
<div class="col-6">
<label class="form-label mb-0 small text-muted">Nama Pimpinan</label>
<input type="text" id="masjidPimpinan" class="form-control form-control-sm" required>
</div>
<div class="col-6">
<label class="form-label mb-0 small text-muted">No Kontak HP</label>
<input type="text" id="masjidHp" class="form-control form-control-sm" required>
</div>
</div>
<div class="mb-2">
<label class="form-label mb-0 small text-muted d-flex justify-content-between">
<span>Rasio Jangkauan Bantuan</span>
<span id="radiusValAdmin" class="fw-bold text-primary">500m</span>
</label>
<input type="range" class="form-range" id="masjidRadius" min="100" max="2000" step="50" value="500">
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label mb-0 small text-muted">Latitude</label>
<input type="text" id="masjidLat" class="form-control form-control-sm" readonly required placeholder="Klik Peta">
</div>
<div class="col-6">
<label class="form-label mb-0 small text-muted">Longitude</label>
<input type="text" id="masjidLng" class="form-control form-control-sm" readonly required placeholder="Klik Peta">
</div>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary btn-sm w-100 fw-semibold">Simpan Data</button>
<button type="button" class="btn btn-dark btn-sm fw-semibold" onclick="batalAksiModeForm('masjid')"><i class="fas fa-times me-1"></i> Batal</button>
</div>
</form>
</div>
</div>
<div id="tabAkun" class="dynamic-section d-none">
<div class="card p-3 border shadow-sm bg-white" style="border-radius:12px;">
<h6 class="fw-bold text-dark mb-3 small"><i class="fas fa-user-plus me-1 text-primary"></i> Buat Akses Akun Baru</h6>
<form id="registerAccountForm">
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Pilih Hak Akses (Role)</label>
<select id="regRole" class="form-select form-select-sm" onchange="handleRoleSelectionChange()" required>
<option value="pengurus_masjid">Pengurus Masjid (Mitra Pengampu)</option>
<option value="dhuafa">Warga Dhuafa (Akses Mandiri)</option>
</select>
</div>
<div class="mb-2" id="regMasjidSelectWrapper">
<label class="form-label mb-0 small text-muted">Tautkan ke Masjid Terdaftar</label>
<select id="regMasjidId" class="form-select form-select-sm"></select>
</div>
<div class="mb-2 d-none" id="regDhuafaSelectWrapper">
<label class="form-label mb-0 small text-muted">Tautkan ke Nama Warga Dhuafa</label>
<select id="regDhuafaId" class="form-select form-select-sm"></select>
</div>
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Username Baru</label>
<input type="text" id="regUsername" class="form-control form-control-sm" required placeholder="Contoh: pengurus_raya">
</div>
<div class="mb-3">
<label class="form-label mb-0 small text-muted">Password Akses</label>
<input type="password" id="regPassword" class="form-control form-control-sm" required placeholder="••••••••">
</div>
<button type="submit" class="btn btn-success btn-sm w-100 fw-semibold">Daftarkan Akun <i class="fas fa-check-circle ms-1"></i></button>
</form>
</div>
</div>
<div class="mt-3">
<div class="row g-2 mb-2">
<div class="col-6">
<div class="card card-stats bg-primary text-white p-2 text-center">
<span class="small-text-muted text-white-50" style="font-size:10px;">TOTAL MASJID</span>
<h4 class="fw-bold my-0" id="statMasjid">0</h4>
</div>
</div>
<div class="col-6">
<div class="card card-stats bg-dark text-white p-2 text-center">
<span class="small-text-muted text-white-50" style="font-size:10px;">TOTAL DHUAFA</span>
<h4 class="fw-bold my-0" id="statDhuafa">0</h4>
</div>
</div>
</div>
<div class="card border p-2 bg-white shadow-sm" style="border-radius:10px;">
<span class="fw-bold text-center d-block text-secondary mb-1" style="font-size:10px; letter-spacing:0.5px;">PERSENTASE CAKUPAN BANTUAN</span>
<div style="width: 130px; margin: 0 auto;">
<canvas id="adminChart" width="130" height="130"></canvas>
</div>
</div>
</div>
</div>
<div id="pengurusWorkspace" class="d-none">
<div class="card bg-gradient border-0 text-white p-3 mb-3 shadow-sm" style="background: linear-gradient(135deg, #2c3e50 0%, #3498db 100%); border-radius:14px;">
<span class="text-white-50 small d-block">Warga Tercover Radius Anda</span>
<h3 class="fw-bold my-0" id="totalWargaPengurus">0 Orang</h3>
<div class="mt-2 text-white-50" style="font-size:11px;"><i class="fas fa-info-circle me-1"></i>Menampilkan warga dhuafa dalam jangkauan radar masjid pengampu anda.</div>
</div>
<div class="mb-2">
<input type="text" id="searchOrangPengurus" class="form-control form-control-sm" placeholder="Cari warga diampu...">
</div>
<div class="table-responsive border rounded bg-white mb-3 shadow-sm" style="max-height: 250px;">
<table class="table table-hover table-sm align-middle mb-0" style="font-size:12px;">
<tbody id="tablePengurusOrangBody"></tbody>
</table>
</div>
<div class="card p-3 border shadow-sm bg-light" style="border-radius:12px;">
<h6 class="fw-bold text-dark mb-2 small"><i class="fas fa-radar me-1 text-primary"></i> Atur Jangkauan Radar Masjid</h6>
<form id="pengurusRadiusForm">
<div class="mb-3">
<label class="form-label mb-0 small text-muted d-flex justify-content-between">
<span>Radius Efektif (Meter)</span>
<span id="radiusValPengurus" class="fw-bold text-primary">500m</span>
</label>
<input type="range" class="form-range" id="sliderRadiusPengurus" min="100" max="2000" step="50" value="500">
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary btn-sm w-100 fw-semibold">Perbarui Radius</button>
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="resetPengurusRadius()"><i class="fas fa-undo"></i></button>
</div>
</form>
</div>
</div>
<div id="dhuafaWorkspace" class="d-none">
<div class="card border shadow-sm p-3 bg-white mb-3" style="border-radius:14px;">
<div class="d-flex justify-content-between align-items-center mb-2">
<span class="fw-bold text-dark small"><i class="fas fa-circle-info text-primary me-1"></i> Status Kelayakan Bantuan</span>
<span id="dhuafaStatusBadge" class="badge">Memuat...</span>
</div>
<div class="p-2 border rounded bg-light" style="font-size:11px;">
<div class="row mb-1">
<div class="col-5 text-muted">Masjid Pengampu:</div>
<div class="col-7 fw-bold text-dark text-end" id="dhuafaInfoMasjid">-</div>
</div>
<div class="row">
<div class="col-5 text-muted">Jarak ke Masjid:</div>
<div class="col-7 fw-bold text-primary text-end" id="dhuafaInfoJarak">-</div>
</div>
</div>
</div>
<div class="card p-3 border shadow-sm bg-white" style="border-radius:12px;">
<h6 class="fw-bold text-dark mb-2 small"><i class="fas fa-user-edit text-success me-1"></i> Profil & Titik Rumah Saya</h6>
<form id="dhuafaSelfForm">
<input type="hidden" id="dhuafaSelfId">
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Nama Lengkap Anda</label>
<input type="text" id="dhuafaSelfNama" class="form-control form-control-sm" required>
</div>
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Nomor Kartu Keluarga (KK)</label>
<input type="text" id="dhuafaSelfKk" class="form-control form-control-sm" required>
</div>
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Nomor Handphone / WA</label>
<input type="text" id="dhuafaSelfHp" class="form-control form-control-sm" required>
</div>
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Alamat Rumah Lengkap</label>
<textarea id="dhuafaSelfAlamat" class="form-control form-control-sm" rows="2" required></textarea>
</div>
<div class="mb-2">
<label class="form-label mb-0 small text-muted">Tanggal Lahir</label>
<input type="date" id="dhuafaSelfTglLahir" class="form-control form-control-sm" required>
</div>
<div class="row g-2 mb-3">
<div class="col-6">
<label class="form-label mb-0 small text-muted">Latitude Rumah</label>
<input type="text" id="dhuafaSelfLat" class="form-control form-control-sm" readonly required>
</div>
<div class="col-6">
<label class="form-label mb-0 small text-muted">Longitude Rumah</label>
<input type="text" id="dhuafaSelfLng" class="form-control form-control-sm" readonly required>
</div>
</div>
<div class="alert alert-warning py-1 px-2 mb-3 shadow-none" style="font-size:10px; line-height:1.3; border-radius:6px;">
<i class="fas fa-location-crosshairs text-danger me-1"></i> Titik kordinat posisi rumah anda saat ini bersifat permanen demi akurasi verifikasi data radar jangkauan masjid pengampu.
</div>
<button type="submit" class="btn btn-success btn-sm w-100 fw-semibold">Simpan Pembaruan Profil <i class="fas fa-save ms-1"></i></button>
</form>
</div>
</div>
</div>
<div id="map"></div>
</div>
<script>
const AUTH_API = 'auth.php';
const APP_API = 'api_masjid.php';
const REG_API = 'register.php';
map = L.map('map').setView([-0.0263, 109.3425], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; OpenStreetMap contributors'
}).addTo(map);
const layerGroupMasjid = L.layerGroup().addTo(map);
const layerGroupOrang = L.layerGroup().addTo(map);
let currentUser = null;
let formActionTarget = 'orang';
let activeFormMarker = null;
let activeFormCircle = null;
let chartInstance = null;
let defaultRadiusBackup = 500;
let markerElementsMapping = {};
let masjidSelesaiLoad = [];
let isModeTambahAktif = false;
function formatTanggalIndo(dateString) {
if (!dateString) return '-';
const parts = dateString.split('-');
if (parts.length !== 3) return dateString;
return `${parts[2]}-${parts[1]}-${parts[0]}`;
}
function switchTab(tabId) {
document.querySelectorAll('.dynamic-section').forEach(el => el.classList.add('d-none'));
document.querySelectorAll('.tab-btn').forEach(el => el.classList.remove('active'));
document.getElementById(tabId).classList.remove('d-none');
document.getElementById('btn' + tabId.charAt(0).toUpperCase() + tabId.slice(1)).classList.add('active');
if(tabId === 'tabMasjid') formActionTarget = 'masjid';
if(tabId === 'tabOrang') formActionTarget = 'orang';
setTimeout(() => { map.invalidateSize(); }, 50);
}
document.addEventListener("DOMContentLoaded", () => {
fetch(`${AUTH_API}?action=check`)
.then(res => res.json())
.then(res => {
if (res.success) { applySessionMode(res.data); }
else { document.getElementById('loginScreen').style.display = 'flex'; }
});
});
document.getElementById('loginForm').addEventListener('submit', (e) => {
e.preventDefault();
fetch(`${AUTH_API}?action=login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: document.getElementById('loginUsername').value,
password: document.getElementById('loginPassword').value
})
}).then(res => res.json()).then(res => {
if (res.success) { applySessionMode(res.data); }
else { alert(res.message); }
});
});
function handleLogout() {
if (!confirm('Apakah anda yakin ingin keluar?')) return;
fetch(`${AUTH_API}?action=logout`, { method: 'POST' }).then(() => location.reload());
}
function applySessionMode(userData) {
currentUser = userData;
document.getElementById('loginScreen').style.display = 'none';
document.getElementById('userBadge').innerText = `Role: ${userData.role.toUpperCase()} (${userData.username})`;
if (currentUser.role === 'pengurus_masjid') {
document.getElementById('navTabsContainer').classList.add('d-none');
document.getElementById('dynamicWorkspace').classList.add('d-none');
document.getElementById('pengurusWorkspace').classList.remove('d-none');
document.getElementById('dhuafaWorkspace').classList.add('d-none');
initPengurusLivePreview();
}
else if (currentUser.role === 'dhuafa') {
document.getElementById('navTabsContainer').classList.add('d-none');
document.getElementById('dynamicWorkspace').classList.add('d-none');
document.getElementById('pengurusWorkspace').classList.add('d-none');
document.getElementById('dhuafaWorkspace').classList.remove('d-none');
formActionTarget = 'dhuafaSelf';
}
else {
document.getElementById('navTabsContainer').classList.remove('d-none');
document.getElementById('dynamicWorkspace').classList.remove('d-none');
document.getElementById('pengurusWorkspace').classList.add('d-none');
document.getElementById('dhuafaWorkspace').classList.add('d-none');
if (currentUser.role === 'admin') {
document.getElementById('btnTabAkun').classList.remove('d-none');
loadAdminChart();
loadDropdownMasjidOptions();
loadDropdownDhuafaOptions();
} else {
document.getElementById('btnTabAkun').classList.add('d-none');
switchTab('tabOrang');
}
initAdminLivePreview();
}
loadMasjid().then(() => {
loadOrang();
});
setTimeout(() => { map.invalidateSize(); }, 100);
}
function initPengurusLivePreview() {
const slider = document.getElementById('sliderRadiusPengurus');
const indicator = document.getElementById('radiusValPengurus');
slider.addEventListener('input', function() {
const nilaiRadius = parseInt(this.value);
indicator.innerText = nilaiRadius + 'm';
layerGroupMasjid.eachLayer(layer => {
if (layer instanceof L.Circle && layer.options.masjidId === parseInt(currentUser.masjid_id)) {
layer.setRadius(nilaiRadius);
}
});
});
}
function initAdminLivePreview() {
const slider = document.getElementById('masjidRadius');
if(slider) {
slider.addEventListener('input', function() {
document.getElementById('radiusValAdmin').innerText = this.value + 'm';
if(activeFormCircle) activeFormCircle.setRadius(this.value);
});
}
}
function aktifkanModeTambah(tipe) {
isModeTambahAktif = true;
tipeModeTambah = tipe;
// Mengubah cursor map menjadi tanda + (cell/crosshair)
const mapContainer = document.getElementById('map');
if (mapContainer) {
mapContainer.classList.add('mode-tambah-aktif');
}
// Menampilkan tombol Batal/Nonaktif di masing-masing form
if (tipe === 'masjid') {
const btnBatalMasjid = document.getElementById('btnBatalMasjid');
if (btnBatalMasjid) btnBatalMasjid.classList.remove('d-none');
alert("Mode tambah masjid aktif. Klik pada peta untuk menentukan lokasi masjid.");
} else if (tipe === 'orang') {
const btnBatalOrang = document.getElementById('btnBatalOrang');
if (btnBatalOrang) btnBatalOrang.classList.remove('d-none');
alert("Mode tambah warga aktif. Klik pada peta untuk menentukan lokasi warga.");
}
}
function batalkanModeTambah() {
isModeTambahAktif = false;
tipeModeTambah = null;
// Mengembalikan cursor map ke normal
const mapContainer = document.getElementById('map');
if (mapContainer) {
mapContainer.classList.remove('mode-tambah-aktif');
}
// Menyembunyikan kembali semua tombol Batal
const btnBatalMasjid = document.getElementById('btnBatalMasjid');
if (btnBatalMasjid) btnBatalMasjid.classList.add('d-none');
const btnBatalOrang = document.getElementById('btnBatalOrang');
if (btnBatalOrang) btnBatalOrang.classList.add('d-none');
// Reset Form & Marker Sementara
resetMasjidForm();
resetOrangForm();
}
// FITUR OTOMATIS: REVERSE GEOCODING (CONVERT LAT LNG TO ALAMAT NYATA IRL)
function fetchAddressFromNominatim(type, lat, lng) {
const textarea = document.getElementById(`${type}Alamat`);
if (!textarea) return;
textarea.placeholder = "Sedang melacak alamat IRL otomatis...";
fetch(`https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}`)
.then(res => res.json())
.then(data => {
if (data && data.display_name) {
textarea.value = data.display_name;
} else {
textarea.placeholder = "Klik peta/geser marker untuk memicu otomatis alamat...";
}
})
.catch(err => {
console.error("Gagal melacak alamat via Nominatim:", err);
textarea.placeholder = "Klik peta/geser marker untuk memicu otomatis alamat...";
});
}
let currentlySelectedMarkerIds = [];
function resetAllSelectedPulses() {
currentlySelectedMarkerIds.forEach(key => {
if (markerElementsMapping[key]) {
const oldMarker = markerElementsMapping[key].marker;
const oldColor = markerElementsMapping[key].originalColor;
if (markerElementsMapping[key].isMasjid) {
oldMarker.setIcon(L.divIcon({
html: `<div style="background-color: #1a365d; color: white; border-radius: 50%; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 6px rgba(0,0,0,0.3);"><i class="fas fa-mosque small"></i></div>`,
className: '', iconSize: [30, 30], iconAnchor: [15, 15]
}));
} else {
oldMarker.setIcon(L.divIcon({
html: `<div style="background-color: ${oldColor}; color: white; border-radius: 50%; width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; border: 2px solid white; box-shadow: 0 2px 5px rgba(0,0,0,0.2);"><i class="fas fa-user small"></i></div>`,
className: '', iconSize: [26, 26], iconAnchor: [13, 13]
}));
}
}
});
currentlySelectedMarkerIds = [];
}
function smoothFocusLocation(lat, lng, targetId, isMasjid = true, triggerIdMasjidPengampu = null) {
resetAllSelectedPulses();
const uniqueKey = (isMasjid ? 'masjid_' : 'orang_') + targetId;
if (markerElementsMapping[uniqueKey]) {
currentlySelectedMarkerIds.push(uniqueKey);
const currentMarker = markerElementsMapping[uniqueKey].marker;
currentMarker.setIcon(L.divIcon({
html: `<div class="selected-masjid-marker"><i class="fas ${isMasjid ? 'fa-mosque' : 'fa-user'}"></i></div>`,
className: '', iconSize: [32, 32], iconAnchor: [16, 16]
}));
currentMarker.openPopup();
}
if (triggerIdMasjidPengampu) {
const masjidKey = 'masjid_' + triggerIdMasjidPengampu;
if (markerElementsMapping[masjidKey]) {
currentlySelectedMarkerIds.push(masjidKey);
const masjidMarker = markerElementsMapping[masjidKey].marker;
masjidMarker.setIcon(L.divIcon({
html: `<div class="selected-masjid-marker"><i class="fas fa-mosque"></i></div>`,
className: '', iconSize: [32, 32], iconAnchor: [16, 16]
}));
}
}
map.flyTo([lat, lng], 15, { animate: true, duration: 1.2 });
}
map.on('click', (e) => {
if (currentUser && currentUser.role === 'dhuafa') return;
if (isModeTambahAktif) {
setFormCoordinates(formActionTarget, e.latlng.lat, e.latlng.lng);
} else {
resetAllSelectedPulses();
}
});
if(document.getElementById('pengurusRadiusForm')) {
document.getElementById('pengurusRadiusForm').addEventListener('submit', (e) => {
e.preventDefault();
const masjidId = currentUser.masjid_id;
const radiusBaru = parseInt(document.getElementById('sliderRadiusPengurus').value);
fetch(`${APP_API}?type=masjid&action=update&id=${masjidId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ radius: radiusBaru })
})
.then(res => res.json())
.then(res => {
alert(res.message);
if(res.success) {
defaultRadiusBackup = radiusBaru;
loadMasjid().then(() => loadOrang());
}
})
.catch(err => {
alert("Gagal memperbarui data jangkauan radius.");
console.error(err);
});
});
}
function resetPengurusRadius() {
document.getElementById('sliderRadiusPengurus').value = defaultRadiusBackup;
document.getElementById('radiusValPengurus').innerText = defaultRadiusBackup + 'm';
layerGroupMasjid.eachLayer(layer => {
if (layer instanceof L.Circle && layer.options.masjidId === parseInt(currentUser.masjid_id)) {
layer.setRadius(defaultRadiusBackup);
}
});
}
function loadMasjid() {
let searchVal = document.getElementById('searchMasjid') ? document.getElementById('searchMasjid').value : '';
return fetch(`${APP_API}?type=masjid&action=getAll&search=${encodeURIComponent(searchVal)}`)
.then(res => res.json())
.then(res => {
layerGroupMasjid.clearLayers();
const tbody = document.getElementById('tableMasjidBody');
if(tbody) tbody.innerHTML = '';
if(res.data) {
masjidSelesaiLoad = res.data;
res.data.forEach(item => {
const mInstance = L.marker([item.latitude, item.longitude], {
icon: L.divIcon({
html: `<div style="background-color: #1a365d; color: white; border-radius: 50%; width: 30px; height: 30px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 6px rgba(0,0,0,0.3);"><i class="fas fa-mosque small"></i></div>`,
className: '', iconSize: [30, 30], iconAnchor: [15, 15]
})
}).addTo(layerGroupMasjid).bindPopup(`
<div style="min-width:220px;">
<b>${escapeHtml(item.nama)}</b><br>
<small><b>Pimpinan:</b> ${escapeHtml(item.nama_pimpinan)}</small><br>
<small><b>HP:</b> ${escapeHtml(item.no_hp)}</small><br>
<small><b>Radius:</b> ${item.radius} m</small>
<hr style="margin:6px 0;">
<small><i class="fas fa-location-dot text-danger"></i> ${escapeHtml(item.alamat)}</small>
</div>
`);
markerElementsMapping['masjid_' + item.id] = {
marker: mInstance, isMasjid: true, originalColor: '#1a365d'
};
const radiusAman = parseInt(item.radius) < 100 ? 500 : parseInt(item.radius);
L.circle([item.latitude, item.longitude], {
radius: radiusAman, color: '#2b6cb0', weight: 1.5, fillOpacity: 0.04, masjidId: parseInt(item.id)
}).addTo(layerGroupMasjid);
if (currentUser && currentUser.role === 'pengurus_masjid' && parseInt(item.id) === parseInt(currentUser.masjid_id)) {
document.getElementById('sliderRadiusPengurus').value = radiusAman;
document.getElementById('radiusValPengurus').innerText = radiusAman + 'm';
defaultRadiusBackup = radiusAman;
setTimeout(() => { smoothFocusLocation(item.latitude, item.longitude, item.id, true); }, 400);
}
if(tbody) {
const tr = document.createElement('tr');
tr.innerHTML = `
<td style="cursor:pointer;" onclick='editMasjid(${JSON.stringify(item).replace(/"/g, "&quot;")})'>
<b>${escapeHtml(item.nama)}</b>
</td>
<td>${radiusAman}m</td>
<td class="text-center"><span class="badge bg-secondary">${item.jumlah_diampu}</span></td>
<td class="text-end"><button class="btn btn-warning btn-xs py-0 px-1" onclick="editMasjid(${JSON.stringify(item).replace(/"/g, '&quot;')})"><i class="fas fa-edit"></i></button> <button class="btn btn-danger btn-xs py-0 px-1" onclick="deleteMasjid(${item.id})"><i class="fas fa-trash"></i></button></td>
`;
tbody.appendChild(tr);
}
});
}
});
}
function loadOrang() {
const queryAdmin = document.getElementById('searchOrang') ? encodeURIComponent(document.getElementById('searchOrang').value) : '';
const queryPengurus = document.getElementById('searchOrangPengurus') ? encodeURIComponent(document.getElementById('searchOrangPengurus').value) : '';
const activeSearch = (currentUser && currentUser.role === 'pengurus_masjid') ? queryPengurus : queryAdmin;
fetch(`${APP_API}?type=orang&action=getAll&search=${activeSearch}`)
.then(res => res.json())
.then(res => {
layerGroupOrang.clearLayers();
const tbodyAdmin = document.getElementById('tableOrangBody');
const tbodyPengurus = document.getElementById('tablePengurusOrangBody');
if(tbodyAdmin) tbodyAdmin.innerHTML = '';
if(tbodyPengurus) tbodyPengurus.innerHTML = '';
let counterWargaPengurus = 0;
if(res.data) {
res.data.forEach(item => {
const color = item.status === 'hijau' ? '#38a169' : '#e53e3e';
const oInstance = L.marker([item.latitude, item.longitude], {
icon: L.divIcon({
html: `<div style="background-color: ${color}; color: white; border-radius: 50%; width: 26px; height: 26px; display: flex; align-items: center; justify-content: center; border: 2px solid white; box-shadow: 0 2px 5px rgba(0,0,0,0.2);"><i class="fas fa-user small"></i></div>`,
className: '', iconSize: [26, 26], iconAnchor: [13, 13]
})
}).addTo(layerGroupOrang).bindPopup(`
<div style="min-width:220px;">
<b>${escapeHtml(item.nama)}</b><br>
<small><b>No KK:</b> ${escapeHtml(item.no_kk)}</small><br>
<small><b>HP:</b> ${escapeHtml(item.no_hp)}</small><br>
<small><b>Pengampu:</b> ${escapeHtml(item.nama_masjid || 'Belum Tercover')}</small><br>
<hr style="margin:6px 0;">
<small><i class="fas fa-location-dot text-danger"></i> ${escapeHtml(item.alamat)}</small>
</div>
`);
markerElementsMapping['orang_' + item.id] = {
marker: oInstance, isMasjid: false, originalColor: color
};
if (currentUser && currentUser.role === 'dhuafa' && parseInt(item.id) === parseInt(currentUser.dhuafa_id)) {
document.getElementById('dhuafaSelfId').value = item.id;
document.getElementById('dhuafaSelfNama').value = item.nama;
document.getElementById('dhuafaSelfKk').value = item.no_kk;
document.getElementById('dhuafaSelfHp').value = item.no_hp;
document.getElementById('dhuafaSelfAlamat').value = item.alamat;
document.getElementById('dhuafaSelfTglLahir').value = item.tgl_lahir;
document.getElementById('dhuafaSelfLat').value = item.latitude;
document.getElementById('dhuafaSelfLng').value = item.longitude;
const badge = document.getElementById('dhuafaStatusBadge');
if (item.status === 'hijau') {
badge.className = "badge bg-success";
badge.innerText = "Telah Diampu";
document.getElementById('dhuafaInfoMasjid').innerText = item.nama_masjid;
document.getElementById('dhuafaInfoJarak').innerText = parseFloat(item.jarak_ke_masjid).toFixed(0) + ' meter';
} else {
badge.className = "badge bg-danger";
badge.innerText = "Belum Diampu";
document.getElementById('dhuafaInfoMasjid').innerText = "Di luar jangkauan radar";
document.getElementById('dhuafaInfoJarak').innerText = "-";
}
if(!activeFormMarker) {
setFormCoordinates('dhuafaSelf', item.latitude, item.longitude);
}
setTimeout(() => {
smoothFocusLocation(item.latitude, item.longitude, item.id, false, item.masjid_pengampu_id);
}, 500);
}
if(tbodyAdmin) {
const trAdmin = document.createElement('tr');
trAdmin.innerHTML = `
<td style="cursor:pointer;" onclick='editOrang(${JSON.stringify(item).replace(/"/g, "&quot;")})'>
<b>${escapeHtml(item.nama)}</b>
</td>
<td class="text-muted small">${escapeHtml(item.no_kk)}</td>
<td><span class="badge ${item.status==='hijau'?'bg-success':'bg-danger'}">${item.status==='hijau'?'Telah Diampu':'Belum Diampu'}</span></td>
<td class="text-end"><button class="btn btn-warning btn-xs py-0 px-1" onclick="editOrang(${JSON.stringify(item).replace(/"/g, '&quot;')})"><i class="fas fa-edit"></i></button> <button class="btn btn-danger btn-xs py-0 px-1" onclick="deleteOrang(${item.id})"><i class="fas fa-trash"></i></button></td>
`;
tbodyAdmin.appendChild(trAdmin);
}
if (currentUser && currentUser.role === 'pengurus_masjid' && parseInt(item.masjid_pengampu_id) === parseInt(currentUser.masjid_id)) {
counterWargaPengurus++;
const jarakFormatted = item.jarak_ke_masjid ? parseFloat(item.jarak_ke_masjid).toFixed(0) + 'm' : '-';
if(tbodyPengurus) {
const trPengurus = document.createElement('tr');
trPengurus.innerHTML = `
<td style="cursor:pointer;" onclick="smoothFocusLocation(${item.latitude}, ${item.longitude}, ${item.id}, false)">
<span class="text-primary fw-bold d-block mb-0">${escapeHtml(item.nama)}</span>
<small class="text-muted d-block text-truncate" style="max-width: 140px;">KK: ${escapeHtml(item.no_kk)}</small>
</td>
<td>
<div class="mb-0 text-dark fw-semibold small"><i class="fa-brands fa-whatsapp text-success me-1"></i>${escapeHtml(item.no_hp)}</div>
<div class="text-muted lh-sm" style="font-size:11px; max-width: 190px;">${escapeHtml(item.alamat)} <br><span class="text-secondary">Lahir: ${escapeHtml(formatTanggalIndo(item.tgl_lahir))}</span></div>
</td>
<td class="text-end text-nowrap">
<span class="badge bg-light text-dark border">${jarakFormatted}</span>
</td>
`;
tbodyPengurus.appendChild(trPengurus);
}
}
});
}
if(document.getElementById('totalWargaPengurus')) {
document.getElementById('totalWargaPengurus').innerText = counterWargaPengurus + ' Orang';
}
});
}
function setFormCoordinates(type, lat, lng) {
if (activeFormMarker) map.removeLayer(activeFormMarker);
if (activeFormCircle) map.removeLayer(activeFormCircle);
const latInput = document.getElementById(`${type}Lat`);
const lngInput = document.getElementById(`${type}Lng`);
if(latInput && lngInput) {
latInput.value = lat;
lngInput.value = lng;
}
if(currentUser && currentUser.role === 'dhuafa') {
map.panTo([lat, lng]);
return;
}
activeFormMarker = L.marker([lat, lng], { draggable: true }).addTo(map);
// Pemicu Pengisian Alamat Nyata Otomatis Saat Pertama Kali Ditandai di Peta
fetchAddressFromNominatim(type, lat, lng);
activeFormMarker.on('dragend', function (event) {
const pos = event.target.getLatLng();
if(latInput && lngInput) {
latInput.value = pos.lat;
lngInput.value = pos.lng;
}
// Pemicu Pengisian Alamat Nyata Otomatis Saat Penanda Digeser (Drag)
fetchAddressFromNominatim(type, pos.lat, pos.lng);
if(type === 'masjid') renderCircleRadiusForm(pos.lat, pos.lng);
});
if (type === 'masjid') { renderCircleRadiusForm(lat, lng); }
}
function renderCircleRadiusForm(lat, lng) {
if (activeFormCircle) map.removeLayer(activeFormCircle);
const sliderAdmin = document.getElementById('masjidRadius');
let radVal = sliderAdmin ? parseInt(sliderAdmin.value) : 500;
if (radVal < 100) radVal = 100;
activeFormCircle = L.circle([lat, lng], { radius: radVal, color: '#1a365d', fillOpacity: 0.15 }).addTo(map);
}
function handleRoleSelectionChange() {
const role = document.getElementById('regRole').value;
const masjidWrapper = document.getElementById('regMasjidSelectWrapper');
const dhuafaWrapper = document.getElementById('regDhuafaSelectWrapper');
if (role === 'pengurus_masjid') {
masjidWrapper.classList.remove('d-none');
dhuafaWrapper.classList.add('d-none');
document.getElementById('regDhuafaId').value = "";
} else if (role === 'dhuafa') {
masjidWrapper.classList.add('d-none');
dhuafaWrapper.classList.remove('d-none');
document.getElementById('regMasjidId').value = "";
}
}
function loadDropdownMasjidOptions() {
fetch(`${APP_API}?type=masjid&action=getAll`).then(res => res.json()).then(res => {
const select = document.getElementById('regMasjidId');
if(!select) return;
select.innerHTML = '<option value="">-- Pilih Masjid Pengampu --</option>';
if(res.data) res.data.forEach(m => select.innerHTML += `<option value="${m.id}">${escapeHtml(m.nama)}</option>`);
});
}
function loadDropdownDhuafaOptions() {
fetch(`${APP_API}?type=orang&action=getAll`).then(res => res.json()).then(res => {
const select = document.getElementById('regDhuafaId');
if(!select) return;
select.innerHTML = '<option value="">-- Pilih Nama Warga Dhuafa --</option>';
if(res.data) res.data.forEach(o => select.innerHTML += `<option value="${o.id}">${escapeHtml(o.nama)} (KK: ${escapeHtml(o.no_kk)})</option>`);
});
}
if(document.getElementById('registerAccountForm')) {
document.getElementById('registerAccountForm').addEventListener('submit', (e) => {
e.preventDefault();
fetch(REG_API, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
role: document.getElementById('regRole').value,
masjid_id: document.getElementById('regMasjidId').value,
dhuafa_id: document.getElementById('regDhuafaId').value,
username: document.getElementById('regUsername').value,
password: document.getElementById('regPassword').value
})
}).then(res => res.json()).then(res => {
alert(res.message);
if(res.success) {
document.getElementById('registerAccountForm').reset();
handleRoleSelectionChange();
loadDropdownDhuafaOptions();
}
});
});
}
if(document.getElementById('dhuafaSelfForm')) {
document.getElementById('dhuafaSelfForm').addEventListener('submit', (e) => {
e.preventDefault();
const id = document.getElementById('dhuafaSelfId').value;
const payload = {
nama: document.getElementById('dhuafaSelfNama').value,
no_kk: document.getElementById('dhuafaSelfKk').value,
alamat: document.getElementById('dhuafaSelfAlamat').value,
tgl_lahir: document.getElementById('dhuafaSelfTglLahir').value,
no_hp: document.getElementById('dhuafaSelfHp').value,
latitude: parseFloat(document.getElementById('dhuafaSelfLat').value),
longitude: parseFloat(document.getElementById('dhuafaSelfLng').value)
};
const url = id ? `${APP_API}?type=orang&action=update&id=${id}` : `${APP_API}?type=orang&action=create`;
fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
.then(res => res.json())
.then(res => {
alert(res.message);
if(res.success) {
loadMasjid().then(() => loadOrang());
}
});
});
}
if(document.getElementById('masjidForm')) {
document.getElementById('masjidForm').addEventListener('submit', (e) => {
e.preventDefault();
const id = document.getElementById('masjidId').value;
const payload = {
nama: document.getElementById('masjidNama').value, alamat: document.getElementById('masjidAlamat').value,
nama_pimpinan: document.getElementById('masjidPimpinan').value, no_hp: document.getElementById('masjidHp').value,
radius: parseInt(document.getElementById('masjidRadius').value),
latitude: parseFloat(document.getElementById('masjidLat').value), longitude: parseFloat(document.getElementById('masjidLng').value)
};
const url = id ? `${APP_API}?type=masjid&action=update&id=${id}` : `${APP_API}?type=masjid&action=create`;
fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })
.then(res => res.json()).then(res => {
alert(res.message); if(res.success) { resetMasjidForm(); loadMasjid().then(() => loadOrang()); loadAdminChart(); loadDropdownMasjidOptions(); isModeTambahAktif = false; }
});
});
}
if(document.getElementById('orangForm')) {
document.getElementById('orangForm').addEventListener('submit', (e) => {
e.preventDefault();
const id = document.getElementById('orangId').value;
const payload = {
nama: document.getElementById('orangNama').value, no_kk: document.getElementById('orangKk').value,
alamat: document.getElementById('orangAlamat').value, tgl_lahir: document.getElementById('orangTglLahir').value,
no_hp: document.getElementById('orangHp').value,
latitude: parseFloat(document.getElementById('orangLat').value), longitude: parseFloat(document.getElementById('orangLng').value)
};
const url = id ? `${APP_API}?type=orang&action=update&id=${id}` : `${APP_API}?type=orang&action=create`;
fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })
.then(res => res.json()).then(res => {
alert(res.message); if(res.success) { resetOrangForm(); loadMasjid().then(() => loadOrang()); loadAdminChart(); loadDropdownDhuafaOptions(); isModeTambahAktif = false; }
});
});
}
function editMasjid(item) {
batalkanModeTambah();
switchTab('tabMasjid');
document.getElementById('masjidId').value = item.id;
document.getElementById('masjidNama').value = item.nama;
document.getElementById('masjidAlamat').value = item.alamat;
document.getElementById('masjidPimpinan').value = item.nama_pimpinan;
document.getElementById('masjidHp').value = item.no_hp;
const radiusEditAman = parseInt(item.radius) < 100 ? 500 : parseInt(item.radius);
document.getElementById('masjidRadius').value = radiusEditAman;
document.getElementById('radiusValAdmin').innerText = radiusEditAman + 'm';
setFormCoordinates('masjid', item.latitude, item.longitude);
smoothFocusLocation(item.latitude, item.longitude, item.id, true);
}
function editOrang(item) {
batalkanModeTambah();
switchTab('tabOrang');
document.getElementById('orangId').value = item.id;
document.getElementById('orangNama').value = item.nama;
document.getElementById('orangKk').value = item.no_kk;
document.getElementById('orangAlamat').value = item.alamat;
document.getElementById('orangTglLahir').value = item.tgl_lahir;
document.getElementById('orangHp').value = item.no_hp;
setFormCoordinates('orang', item.latitude, item.longitude);
smoothFocusLocation(item.latitude, item.longitude, item.id, false, item.masjid_pengampu_id);
}
function deleteMasjid(id) {
if(!confirm('Hapus masjid ini?')) return;
fetch(`${APP_API}?type=masjid&action=delete&id=${id}`, { method: 'POST' }).then(() => { loadMasjid().then(() => loadOrang()); loadAdminChart(); loadDropdownMasjidOptions(); });
}
function deleteOrang(id) {
if(!confirm('Hapus data warga dhuafa ini?')) return;
fetch(`${APP_API}?type=orang&action=delete&id=${id}`, { method: 'POST' }).then(() => { loadMasjid().then(() => loadOrang()); loadAdminChart(); loadDropdownDhuafaOptions(); });
}
function loadAdminChart() {
const chartCanvas = document.getElementById('adminChart');
if(!chartCanvas) return;
fetch(`${APP_API}?type=summary`).then(res => res.json()).then(res => {
if(res.data) {
document.getElementById('statMasjid').innerText = res.data.total_masjid;
document.getElementById('statDhuafa').innerText = res.data.total_dhuafa;
const ctx = chartCanvas.getContext('2d');
if (chartInstance) chartInstance.destroy();
chartInstance = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ['Telah Diampu', 'Belum Diampu'],
datasets: [{ data: [res.data.terampu, res.data.belum_terampu], backgroundColor: ['#38a169', '#e53e3e'], borderWidth: 1 }]
},
options: { responsive: true, plugins: { legend: { position: 'bottom', labels: { boxWidth: 12, font: { size: 11 } } } } }
});
}
});
}
function resetMasjidForm() {
document.getElementById('masjidForm').reset();
document.getElementById('masjidId').value = '';
document.getElementById('radiusValAdmin').innerText = "500m";
document.getElementById('map').classList.remove('mode-tambah-aktif');
isModeTambahAktif = false;
if(activeFormMarker) map.removeLayer(activeFormMarker);
if(activeFormCircle) map.removeLayer(activeFormCircle);
}
function resetOrangForm() {
document.getElementById('orangForm').reset();
document.getElementById('orangId').value = '';
document.getElementById('map').classList.remove('mode-tambah-aktif');
isModeTambahAktif = false;
if(activeFormMarker) map.removeLayer(activeFormMarker);
}
// ============================================================
// 📍 KODE BARU LANGKAH 2 (Fungsi Mode Tambah & Batal Tambah)
// ============================================================
function aktifkanModeTambah(type) {
isModeTambahAktif = true;
formActionTarget = type;
document.getElementById('map').classList.add('mode-tambah-aktif');
if (type === 'masjid') {
resetMasjidForm();
alert("Mode Tambah AKTIF: Silakan KLIK pada peta untuk menentukan titik koordinat MASJID baru.");
} else {
resetOrangForm();
alert("Mode Tambah AKTIF: Silakan KLIK pada peta untuk menentukan titik koordinat DHUAFA baru.");
}
}
function batalkanModeTambah() {
isModeTambahAktif = false;
formActionTarget = null;
document.getElementById('map').classList.remove('mode-tambah-aktif');
if (activeFormMarker) map.removeLayer(activeFormMarker);
if (activeFormCircle) map.removeLayer(activeFormCircle);
resetMasjidForm();
resetOrangForm();
}
// ============================================================
// 📍 KODE BARU LANGKAH 3 (Event Listener Submit / Tombol Simpan)
// ============================================================
document.getElementById('masjidForm').addEventListener('submit', function(e) {
e.preventDefault();
const id = document.getElementById('masjidId').value;
const lat = document.getElementById('masjidLat').value; // Sesuai id input masjidLat Anda
const lng = document.getElementById('masjidLng').value; // Sesuai id input masjidLng Anda
if (!lat || !lng) {
alert("Silakan tentukan lokasi koordinat masjid di peta terlebih dahulu!");
return;
}
const payload = {
nama: document.getElementById('masjidNama').value,
alamat: document.getElementById('masjidAlamat').value,
nama_pimpinan: document.getElementById('masjidPimpinan').value,
no_hp: document.getElementById('masjidHp').value,
radius: parseInt(document.getElementById('masjidRadius').value),
latitude: parseFloat(lat),
longitude: parseFloat(lng)
};
const action = id ? 'update' : 'create';
const url = id ? `${APP_API}?type=masjid&action=${action}&id=${id}` : `${APP_API}?type=masjid&action=${action}`;
fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })
.then(res => res.json())
.then(res => {
alert(res.message);
if (res.success) {
batalkanModeTambah();
loadMasjid().then(() => loadOrang());
}
}).catch(err => alert("Gagal menyimpan data masjid."));
});
document.getElementById('orangForm').addEventListener('submit', function(e) {
e.preventDefault();
const id = document.getElementById('orangId').value;
const lat = document.getElementById('orangLat').value; // Sesuai id input orangLat Anda
const lng = document.getElementById('orangLng').value; // Sesuai id input orangLng Anda
if (!lat || !lng) {
alert("Silakan tentukan lokasi koordinat warga di peta terlebih dahulu!");
return;
}
const payload = {
nama: document.getElementById('orangNama').value,
no_kk: document.getElementById('orangKk').value,
no_hp: document.getElementById('orangHp').value,
alamat: document.getElementById('orangAlamat').value,
tgl_lahir: document.getElementById('orangTglLahir').value,
latitude: parseFloat(lat),
longitude: parseFloat(lng)
};
const action = id ? 'update' : 'create';
const url = id ? `${APP_API}?type=orang&action=${action}&id=${id}` : `${APP_API}?type=orang&action=${action}`;
fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })
.then(res => res.json())
.then(res => {
alert(res.message);
if (res.success) {
batalkanModeTambah();
loadMasjid().then(() => loadOrang());
}
}).catch(err => alert("Gagal menyimpan data warga."));
});
function escapeHtml(text) {
if (!text) return '';
return text.toString().replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;").replace(/'/g, "&#039;");
}
if(document.getElementById('searchMasjid')) document.getElementById('searchMasjid').addEventListener('input', () => loadMasjid());
if(document.getElementById('searchOrang')) document.getElementById('searchOrang').addEventListener('input', () => loadOrang());
if(document.getElementById('searchOrangPengurus')) document.getElementById('searchOrangPengurus').addEventListener('input', () => loadOrang());
</script>
</body>
</html>