310 lines
14 KiB
PHP
310 lines
14 KiB
PHP
<?php $extraJs = <<<JS
|
||
<script>
|
||
let riMap = null;
|
||
let riMarker = null;
|
||
|
||
function openTambahModal() {
|
||
App.showModal('modal-tambah');
|
||
setTimeout(() => {
|
||
if (!riMap) {
|
||
riMap = L.map('ri-map-tambah').setView([-0.0263, 109.3425], 13);
|
||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{maxZoom:19}).addTo(riMap);
|
||
riMap.on('click', e => placeRIMarker(e.latlng.lat, e.latlng.lng, 'tambah'));
|
||
}
|
||
riMap.invalidateSize();
|
||
}, 300);
|
||
}
|
||
|
||
function placeRIMarker(lat, lng, mode) {
|
||
const m = mode === 'tambah' ? riMap : editMap;
|
||
const prefix = mode === 'tambah' ? '' : 'edit-';
|
||
if (riMarker) m.removeLayer(riMarker);
|
||
riMarker = L.marker([lat, lng], { draggable: true }).addTo(m);
|
||
document.getElementById(prefix + 'lat').value = lat.toFixed(7);
|
||
document.getElementById(prefix + 'lng').value = lng.toFixed(7);
|
||
riMarker.on('dragend', e => {
|
||
const pos = e.target.getLatLng();
|
||
document.getElementById(prefix + 'lat').value = pos.lat.toFixed(7);
|
||
document.getElementById(prefix + 'lng').value = pos.lng.toFixed(7);
|
||
});
|
||
}
|
||
|
||
function openEditModal(ri) {
|
||
document.getElementById('edit-nama').value = ri.nama;
|
||
document.getElementById('edit-alamat').value = ri.alamat || '';
|
||
document.getElementById('edit-id_jenis').value = ri.id_jenis;
|
||
document.getElementById('edit-id_kelurahan').value = ri.id_kelurahan;
|
||
document.getElementById('edit-radius_meter').value = ri.radius_meter;
|
||
document.getElementById('edit-nama_ketua').value = ri.nama_ketua || '';
|
||
document.getElementById('edit-no_hp_pengurus').value = ri.no_hp_pengurus || '';
|
||
document.getElementById('edit-lat').value = ri.lat;
|
||
document.getElementById('edit-lng').value = ri.lng;
|
||
document.getElementById('edit-is_active').value = ri.is_active;
|
||
document.getElementById('edit-form').action = '<?= APP_URL ?>/admin/rumah-ibadah/' + ri.id + '/update';
|
||
App.showModal('modal-edit');
|
||
}
|
||
</script>
|
||
JS; ?>
|
||
|
||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:20px">
|
||
<div>
|
||
<h2 style="font-size:1.2rem;font-weight:700">Manajemen Rumah Ibadah</h2>
|
||
<p class="text-muted text-sm">Total <?= count($data) ?> rumah ibadah terdaftar</p>
|
||
</div>
|
||
<button class="btn btn-primary" onclick="openTambahModal()">➕ Tambah Rumah Ibadah</button>
|
||
</div>
|
||
|
||
<!-- PETA RUMAH IBADAH -->
|
||
<div class="card" style="margin-bottom:20px">
|
||
<div class="card-header"><span class="card-icon">🗺</span><h3>Peta Rumah Ibadah</h3></div>
|
||
<div class="card-body no-pad">
|
||
<div id="ri-overview-map" style="height:320px"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- SEARCH -->
|
||
<div class="filters-bar">
|
||
<input type="text" id="search-ri" class="form-control" placeholder="🔍 Cari nama, kelurahan..." style="max-width:300px">
|
||
</div>
|
||
|
||
<!-- TABLE -->
|
||
<div class="card">
|
||
<div class="card-body no-pad">
|
||
<div class="table-wrap">
|
||
<table id="table-ri">
|
||
<thead>
|
||
<tr><th>#</th><th>Nama</th><th>Jenis</th><th>Wilayah</th><th>Ketua</th><th>Radius</th><th>Warga Binaan</th><th>Status</th><th>Aksi</th></tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach ($data as $i => $r): ?>
|
||
<tr>
|
||
<td class="text-muted text-xs"><?= $i+1 ?></td>
|
||
<td>
|
||
<div style="font-weight:600;font-size:0.875rem"><?= e($r['nama']) ?></div>
|
||
<div class="text-muted text-xs"><?= e($r['alamat'] ?? '') ?></div>
|
||
</td>
|
||
<td><span class="badge badge-green"><?= e($r['jenis']) ?></span></td>
|
||
<td class="text-sm"><?= e($r['kecamatan']) ?> › <?= e($r['kelurahan']) ?></td>
|
||
<td class="text-sm"><?= e($r['nama_ketua'] ?? '—') ?></td>
|
||
<td class="text-sm"><?= number_format($r['radius_meter']) ?>m</td>
|
||
<td><strong><?= number_format($r['jml_warga']) ?></strong> warga</td>
|
||
<td><?= $r['is_active'] ? '<span class="badge badge-green">Aktif</span>' : '<span class="badge badge-gray">Nonaktif</span>' ?></td>
|
||
<td>
|
||
<div style="display:flex;gap:6px">
|
||
<button class="btn btn-ghost btn-sm" onclick='openEditModal(<?= json_encode($r) ?>)'>✏️</button>
|
||
<form method="POST" action="<?= APP_URL ?>/admin/rumah-ibadah/<?= $r['id'] ?>/delete"
|
||
onsubmit="return confirm('Nonaktifkan <?= addslashes($r['nama']) ?>?')">
|
||
<?= csrfField() ?>
|
||
<button type="submit" class="btn btn-ghost btn-sm" style="color:var(--clr-danger)">🗑</button>
|
||
</form>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MODAL TAMBAH -->
|
||
<div class="modal-overlay" id="modal-tambah">
|
||
<div class="modal" style="max-width:680px">
|
||
<div class="modal-header">
|
||
<h3>➕ Tambah Rumah Ibadah</h3>
|
||
<button class="modal-close" onclick="App.hideModal('modal-tambah')">✕</button>
|
||
</div>
|
||
<form method="POST" action="<?= APP_URL ?>/admin/rumah-ibadah/store" enctype="multipart/form-data">
|
||
<?= csrfField() ?>
|
||
<div class="modal-body">
|
||
<div class="form-group">
|
||
<label class="form-label">Nama Rumah Ibadah <span class="required">*</span></label>
|
||
<input type="text" name="nama" class="form-control" required>
|
||
</div>
|
||
<div class="form-row cols-2">
|
||
<div class="form-group">
|
||
<label class="form-label">Jenis <span class="required">*</span></label>
|
||
<select name="id_jenis" class="form-control" required>
|
||
<?php foreach ($jenis as $j): ?>
|
||
<option value="<?= $j['id'] ?>"><?= e($j['nama']) ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Kelurahan <span class="required">*</span></label>
|
||
<select name="id_kelurahan" class="form-control" required>
|
||
<?php foreach ($kelurahan as $k): ?>
|
||
<option value="<?= $k['id'] ?>"><?= e($k['nama']) ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Alamat</label>
|
||
<input type="text" name="alamat" class="form-control">
|
||
</div>
|
||
<div class="form-row cols-2">
|
||
<div class="form-group">
|
||
<label class="form-label">Nama Ketua/Pengurus</label>
|
||
<input type="text" name="nama_ketua" class="form-control">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">No HP Pengurus</label>
|
||
<input type="text" name="no_hp_pengurus" class="form-control">
|
||
</div>
|
||
</div>
|
||
<div class="form-row cols-2">
|
||
<div class="form-group">
|
||
<label class="form-label">Akun Pengurus</label>
|
||
<select name="id_user" class="form-control">
|
||
<option value="">— Belum Ada —</option>
|
||
<?php foreach ($pengurusAvail as $p): ?>
|
||
<option value="<?= $p['id'] ?>"><?= e($p['nama']) ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Radius Pelayanan (meter) <span class="required">*</span></label>
|
||
<input type="number" name="radius_meter" class="form-control" value="500" min="100" max="5000" required>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label class="form-label">📍 Pilih Lokasi pada Peta <span class="required">*</span></label>
|
||
<div id="ri-map-tambah" style="height:220px;border-radius:8px;border:1px solid var(--clr-border)"></div>
|
||
<div class="form-row cols-2" style="margin-top:8px">
|
||
<input type="number" name="lat" id="lat" class="form-control" placeholder="Latitude" step="0.0000001" required>
|
||
<input type="number" name="lng" id="lng" class="form-control" placeholder="Longitude" step="0.0000001" required>
|
||
</div>
|
||
<div class="form-hint">Klik pada peta untuk menandai lokasi</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Foto</label>
|
||
<input type="file" name="foto" class="form-control" accept="image/*">
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-ghost" onclick="App.hideModal('modal-tambah')">Batal</button>
|
||
<button type="submit" class="btn btn-primary">Simpan</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MODAL EDIT -->
|
||
<div class="modal-overlay" id="modal-edit">
|
||
<div class="modal" style="max-width:560px">
|
||
<div class="modal-header">
|
||
<h3>✏️ Edit Rumah Ibadah</h3>
|
||
<button class="modal-close" onclick="App.hideModal('modal-edit')">✕</button>
|
||
</div>
|
||
<form method="POST" id="edit-form" enctype="multipart/form-data">
|
||
<?= csrfField() ?>
|
||
<div class="modal-body">
|
||
<div class="form-group">
|
||
<label class="form-label">Nama <span class="required">*</span></label>
|
||
<input type="text" name="nama" id="edit-nama" class="form-control" required>
|
||
</div>
|
||
<div class="form-row cols-2">
|
||
<div class="form-group">
|
||
<label class="form-label">Jenis</label>
|
||
<select name="id_jenis" id="edit-id_jenis" class="form-control">
|
||
<?php foreach ($jenis as $j): ?>
|
||
<option value="<?= $j['id'] ?>"><?= e($j['nama']) ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Kelurahan</label>
|
||
<select name="id_kelurahan" id="edit-id_kelurahan" class="form-control">
|
||
<?php foreach ($kelurahan as $k): ?>
|
||
<option value="<?= $k['id'] ?>"><?= e($k['nama']) ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Alamat</label>
|
||
<input type="text" name="alamat" id="edit-alamat" class="form-control">
|
||
</div>
|
||
<div class="form-row cols-2">
|
||
<div class="form-group">
|
||
<label class="form-label">Nama Ketua</label>
|
||
<input type="text" name="nama_ketua" id="edit-nama_ketua" class="form-control">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">No HP</label>
|
||
<input type="text" name="no_hp_pengurus" id="edit-no_hp_pengurus" class="form-control">
|
||
</div>
|
||
</div>
|
||
<div class="form-row cols-3">
|
||
<div class="form-group">
|
||
<label class="form-label">Radius (m)</label>
|
||
<input type="number" name="radius_meter" id="edit-radius_meter" class="form-control">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Status</label>
|
||
<select name="is_active" id="edit-is_active" class="form-control">
|
||
<option value="1">Aktif</option><option value="0">Nonaktif</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Foto Baru</label>
|
||
<input type="file" name="foto" class="form-control" accept="image/*">
|
||
</div>
|
||
</div>
|
||
<div class="form-row cols-2">
|
||
<div class="form-group">
|
||
<label class="form-label">Latitude</label>
|
||
<input type="number" name="lat" id="edit-lat" class="form-control" step="0.0000001">
|
||
</div>
|
||
<div class="form-group">
|
||
<label class="form-label">Longitude</label>
|
||
<input type="number" name="lng" id="edit-lng" class="form-control" step="0.0000001">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<button type="button" class="btn btn-ghost" onclick="App.hideModal('modal-edit')">Batal</button>
|
||
<button type="submit" class="btn btn-primary">Simpan Perubahan</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', async () => {
|
||
App.initTableSearch('search-ri', 'table-ri');
|
||
|
||
// Overview map
|
||
const ovMap = L.map('ri-overview-map').setView([-0.0263, 109.3425], 12);
|
||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',{maxZoom:19}).addTo(ovMap);
|
||
|
||
const riData = <?= json_encode(array_map(fn($r) => [
|
||
'id'=>$r['id'],'nama'=>$r['nama'],'lat'=>(float)$r['lat'],'lng'=>(float)$r['lng'],
|
||
'radius_meter'=>$r['radius_meter'],'jenis'=>$r['jenis'],'kelurahan'=>$r['kelurahan'],
|
||
'jml_warga'=>$r['jml_warga'],'is_active'=>$r['is_active']
|
||
], $data)) ?>;
|
||
|
||
const riBounds = [];
|
||
riData.forEach(ri => {
|
||
if (!ri.lat || !ri.lng) return;
|
||
const lat = parseFloat(ri.lat), lng = parseFloat(ri.lng);
|
||
if (isNaN(lat)||isNaN(lng)) return;
|
||
const icon = L.divIcon({
|
||
className:'',
|
||
html:`<div style="background:${ri.is_active?'#16a34a':'#6b7280'};color:#fff;padding:4px 8px;border-radius:4px;font-size:11px;font-weight:700;white-space:nowrap;box-shadow:0 2px 4px rgba(0,0,0,0.2)">${ri.nama}</div>`,
|
||
iconAnchor:[0,0]
|
||
});
|
||
L.marker([lat,lng],{icon}).bindPopup(`<strong>${ri.nama}</strong><br>${ri.jenis}<br>${ri.kelurahan}<br>Radius: ${ri.radius_meter}m<br>Warga: ${ri.jml_warga}`).addTo(ovMap);
|
||
L.circle([lat,lng],{radius:ri.radius_meter,fillColor:'#16a34a',fillOpacity:0.08,color:'#16a34a',weight:1.5,dashArray:'4,4'}).addTo(ovMap);
|
||
riBounds.push([lat,lng]);
|
||
});
|
||
// Auto-zoom ke seluruh rumah ibadah Kota Pontianak
|
||
if (riBounds.length > 0) {
|
||
const b = L.latLngBounds(riBounds);
|
||
if (b.isValid()) ovMap.flyToBounds(b, {duration:0.6, padding:[30,30], maxZoom:14});
|
||
}
|
||
});
|
||
</script>
|