Compare commits

..

2 Commits

Author SHA1 Message Date
raditarahman5-cloud f5043b13d7 fix: hapus gembok login agar bisa simpan data langsung 2026-06-13 01:07:22 +07:00
raditarahman5-cloud 1b44fc6a8f fix: session cookie path across directories 2026-06-13 00:35:11 +07:00
11 changed files with 309 additions and 199 deletions
+103
View File
@@ -0,0 +1,103 @@
# Draft Dokumen Pengumpulan Project Ujian/Tugas WebGIS
Berdasarkan screenshot form pengumpulan tugas yang Anda berikan, berikut adalah draft untuk dokumen-dokumen yang perlu disiapkan:
## 1. Dokumen Panduan Pengguna (User Guide) Aplikasi WebGIS
*(Simpan sebagai file PDF/Word)*
**Judul:** Panduan Pengguna WebGIS Poverty Mapping (Pusat Integrasi Data GIS Kota Pontianak)
**Daftar Isi:**
1. **Pendahuluan:** Penjelasan singkat tentang aplikasi WebGIS Poverty Mapping.
2. **Cara Mengakses Aplikasi:** URL/Link aplikasi dan cara masuk ke Portal Utama.
3. **Modul Fasilitas & Tata Kota (Infrastruktur):**
- Cara melihat data spasial fasilitas umum dan jaringan jalan raya.
- Cara melihat batas kepemilikan lahan dan lokasi SPBU.
- (Jika ada fitur admin/login) Cara menambah atau mengubah data spasial infrastruktur.
4. **Modul Sosial & Kemasyarakatan:**
- Cara memetakan dan melihat kawasan rentan serta distribusi penduduk.
- Cara melihat pemantauan rumah ibadah dan data laporan darurat.
5. **Modul Portal Publik (Warga):**
- Cara warga mengakses aplikasi secara publik (tanpa login).
- Cara warga melihat fasilitas umum terdekat.
- Cara warga melakukan pelaporan cepat kedaruratan.
---
## 2. Dokumen Spesifikasi Kebutuhan Perangkat Lunak (SKPL)
*(Simpan sebagai file PDF/Word)*
**Judul:** Spesifikasi Kebutuhan Perangkat Lunak (SKPL) - WebGIS Poverty Mapping
**1. Pendahuluan**
- **Tujuan:** Mendokumentasikan kebutuhan fungsional dan non-fungsional aplikasi WebGIS Poverty Mapping.
- **Ruang Lingkup:** Aplikasi berbasis web untuk pemetaan kemiskinan, fasilitas umum, dan pelaporan darurat di Kota Pontianak.
**2. Deskripsi Umum Sistem**
- Aplikasi ini terdiri dari 3 modul utama: Portal Infrastruktur, Portal Sosial, dan Portal Warga.
- Pengguna sistem terdiri dari: Admin (pengelola data) dan Masyarakat Umum (warga).
**3. Kebutuhan Fungsional (Functional Requirements)**
- **FR-01:** Sistem harus dapat menampilkan peta dasar (base map) menggunakan Leaflet.js atau sejenisnya.
- **FR-02:** Sistem menyediakan fitur bagi Admin untuk mengelola (CRUD) data fasilitas umum, SPBU, jalan raya, dan persil tanah (Modul Infrastruktur).
- **FR-03:** Sistem menyediakan fitur bagi Admin untuk memantau data demografi/sosial, rumah ibadah, dan melihat laporan darurat (Modul Sosial).
- **FR-04:** Sistem memungkinkan warga (tanpa login) untuk melihat peta titik-titik fasilitas, serta mengisi form pelaporan kejadian darurat.
- **FR-05:** Sistem memungkinkan warga menarik/drag pin pada peta untuk menentukan koordinat kejadian secara akurat.
**4. Kebutuhan Non-Fungsional (Non-Functional Requirements)**
- **Ketersediaan (Availability):** Aplikasi dapat diakses 24/7 melalui browser web.
- **Keamanan (Security):** Sistem dirancang terbuka (tanpa otentikasi login yang ketat) untuk memudahkan masyarakat dan petugas lapangan dalam menginput data secara langsung.
- **Performa:** Peta dan marker harus dapat dimuat dalam waktu kurang dari 5 detik pada koneksi internet standar.
---
## 3. Slide Presentasi
*(Buat di PowerPoint / Google Slides dan simpan sebagai PDF/PPT)*
**Slide 1: Judul Project**
- Nama Project: WebGIS Poverty Mapping (Pusat Integrasi Data GIS Kota Pontianak)
- Nama / NIM Kelompok Anda
**Slide 2: Latar Belakang & Tujuan**
- Mengapa aplikasi ini dibuat? (Untuk mengintegrasikan data spasial kemiskinan, infrastruktur, sosial, dan memfasilitasi pelaporan warga).
- Manfaat bagi pemerintah dan masyarakat.
**Slide 3: Arsitektur / Teknologi yang Digunakan**
- Frontend: HTML, CSS, JavaScript, Leaflet.js (untuk peta).
- Backend: PHP.
- Database: MySQL / MariaDB (Menyimpan titik koordinat dan data).
- Server/Hosting: Coolify (jika sudah di-deploy) / Localhost XAMPP.
**Slide 4: Fitur Utama: Modul Infrastruktur & Sosial**
- Screenshot halaman Dashboard Admin (Infrastruktur & Sosial).
- Penjelasan singkat fitur (Manajemen SPBU, fasilitas umum, demografi).
**Slide 5: Fitur Utama: Modul Warga (Publik)**
- Screenshot halaman Portal Warga.
- Penjelasan alur warga melakukan pelaporan darurat menggunakan *draggable map markers*.
**Slide 6: Demo Singkat (Opsional)**
- Siapkan link / video demo singkat penggunaan aplikasi.
**Slide 7: Kesimpulan & Penutup**
- Kesimpulan keberhasilan project.
- Sesi tanya jawab.
---
## 4. Persiapan File Project (.ZIP)
Form meminta 2 file ZIP: **Upload File Project WebGIS Poverty Map** dan **Upload File Project Tugas di Kelas**.
**Langkah membuat ZIP:**
1. Buka folder `c:\Webargis\webgis01` (atau folder utama project Anda).
2. Pastikan file database (`.sql`) sudah diekspor dan dimasukkan ke dalam folder project. Saya melihat ada file `CREATE DATABASE webgis_spbu;.sql`, pastikan ini adalah versi terbaru dari database Anda.
3. Blok semua file & folder di dalam `webgis01` (`api`, `infra`, `portal`, `sosial`, `warga`, `index.php`, `test.php`, `.sql`, dll).
4. Klik kanan -> Send to -> **Compressed (zipped) folder** (atau gunakan WinRAR/7-zip).
5. Beri nama file ZIP tersebut sesuai format tugas, misalnya:
- `Project_WebGIS_Poverty_Map_Nama_NIM.zip`
- `Project_Tugas_Kelas_Nama_NIM.zip`
6. Upload kedua file ZIP ini di form.
---
Silakan salin teks di atas ke Microsoft Word atau PowerPoint untuk melengkapi tugas Anda. Apakah Anda butuh bantuan untuk membuat dokumen secara utuh dalam format PDF/Word melalui kode?
+2 -1
View File
@@ -1,4 +1,5 @@
<?php
session_set_cookie_params(['path' => '/']);
session_start();
$is_public_action = ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'simpan_pelaporan');
@@ -27,7 +28,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$allowed_sosial_actions = ['simpan_warga', 'simpan_masjid', 'simpan_pelaporan'];
$allowed_sosial_tables = ['warga', 'rumah_ibadah', 'pelaporan'];
$is_authorized = false;
$is_authorized = true; // Bypassed for demo/user request
if (in_array($role, ['admin', 'admin_infra', 'admin_sosial'])) {
$is_authorized = true;
+1
View File
@@ -1,4 +1,5 @@
<?php
session_set_cookie_params(['path' => '/']);
session_start();
require_once '../api/db.php';
+44 -44
View File
@@ -37,7 +37,7 @@ var cachedData = null;
var drawControl = new L.Control.Draw({
draw: {
marker:false, circle:false, circlemarker:false,
marker: false, circle: false, circlemarker: false,
polyline: { shapeOptions: { color: 'blue', weight: 4 } },
polygon: { shapeOptions: { color: 'red' } },
rectangle: false
@@ -47,7 +47,7 @@ var drawControl = new L.Control.Draw({
map.addControl(drawControl);
// Locate Control
var locateBtn = L.control({position: 'topleft'});
var locateBtn = L.control({ position: 'topleft' });
locateBtn.onAdd = function (map) {
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
div.style.backgroundColor = 'white';
@@ -59,13 +59,13 @@ locateBtn.onAdd = function (map) {
div.style.justifyContent = 'center';
div.innerHTML = '<i class="fas fa-crosshairs" style="font-size:1.2rem; color:#2563eb;"></i>';
div.title = "Lokasi Anda Saat Ini";
div.onclick = function(){ map.locate({setView: true, maxZoom: 16}); }
div.onclick = function () { map.locate({ setView: true, maxZoom: 16 }); }
return div;
};
locateBtn.addTo(map);
map.on('locationfound', function(e) {
L.circleMarker(e.latlng, {radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1}).addTo(map).bindPopup("Lokasi Anda").openPopup();
map.on('locationfound', function (e) {
L.circleMarker(e.latlng, { radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1 }).addTo(map).bindPopup("Lokasi Anda").openPopup();
});
// Event Draw
@@ -103,7 +103,7 @@ map.on(L.Draw.Event.CREATED, function (e) {
map.on(L.Draw.Event.EDITED, function (e) {
var layers = e.layers;
layers.eachLayer(function (layer) {
if(layer.db_id && layer.db_tipe) {
if (layer.db_id && layer.db_tipe) {
var coords = (layer.db_tipe === 'parsil') ? layer.getLatLngs()[0] : layer.getLatLngs();
var fd = new FormData();
fd.append('action', 'update_koordinat');
@@ -111,7 +111,7 @@ map.on(L.Draw.Event.EDITED, function (e) {
fd.append('tipe', layer.db_tipe);
fd.append('koordinat', JSON.stringify(coords));
if(layer.db_tipe === 'jalan') {
if (layer.db_tipe === 'jalan') {
var length = 0;
for (var i = 0; i < coords.length - 1; i++) {
length += coords[i].distanceTo(coords[i + 1]);
@@ -121,13 +121,13 @@ map.on(L.Draw.Event.EDITED, function (e) {
fetch('../api/api.php', { method: 'POST', body: fd });
}
});
Swal.fire({icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false});
Swal.fire({ icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false });
});
map.on(L.Draw.Event.DELETED, function (e) {
var layers = e.layers;
layers.eachLayer(function (layer) {
if(layer.db_id && layer.db_tipe) {
if (layer.db_id && layer.db_tipe) {
var fd = new FormData();
fd.append('action', 'hapus_data');
fd.append('id', layer.db_id);
@@ -135,20 +135,20 @@ map.on(L.Draw.Event.DELETED, function (e) {
fetch('../api/api.php', { method: 'POST', body: fd });
}
});
Swal.fire({icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false});
Swal.fire({ icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false });
});
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('active'); }
function toggleRightPanel() {
var panel = document.getElementById('panelInput');
if(panel) panel.classList.toggle('collapsed');
if (panel) panel.classList.toggle('collapsed');
}
function filterData() {
var input = document.getElementById('searchInput').value.toLowerCase();
var cards = document.getElementsByClassName('item-data');
if(input.length > 0) document.getElementById('sidebar').classList.add('active');
if (input.length > 0) document.getElementById('sidebar').classList.add('active');
for (var i = 0; i < cards.length; i++) {
cards[i].style.display = cards[i].getAttribute('data-nama').includes(input) ? "" : "none";
}
@@ -157,7 +157,7 @@ function filterData() {
function changeRadius(v) {
currentRadius = parseInt(v);
document.getElementById('radiusVal').innerText = v;
if(cachedData) renderMap(cachedData);
if (cachedData) renderMap(cachedData);
}
var prevReportCount = -1;
@@ -183,8 +183,8 @@ function loadData(isPolling = false) {
prevReportCount = data.pelaporan.length;
var badge = document.getElementById('notifBadge');
if(badge) {
if(data.pelaporan.length > 0) {
if (badge) {
if (data.pelaporan.length > 0) {
badge.style.display = 'block';
badge.innerText = data.pelaporan.length;
} else {
@@ -208,7 +208,7 @@ function loadData(isPolling = false) {
// Auto-poll every 10 seconds
setInterval(() => {
// Only poll if not currently editing (edit_id is 0)
if(document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
if (document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
loadData(true);
}
}, 10000);
@@ -238,12 +238,12 @@ function renderSidebar(data) {
if (!window.dashboardType || window.dashboardType === 'sosial' || window.dashboardType === 'admin') {
// Pelaporan
html += `<div class="section-title" style="color:#ef4444">🚨 Laporan Darurat</div>`;
if(data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
if (data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
data.pelaporan.forEach(p => {
html += `<div class="card item-data" data-nama="${p.nama_pelapor.toLowerCase()} ${p.isi_laporan.toLowerCase()}">
<div style="display:flex; justify-content:space-between">
<span onclick="fokus(${p.latitude}, ${p.longitude})" style="cursor:pointer">
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0,40)}...</span>
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0, 40)}...</span>
</span>
<div>
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-bottom:5px;" onclick="editData('pelaporan', ${p.id})">Edit</button><br>
@@ -313,9 +313,9 @@ function renderSidebar(data) {
html += `<div class="section-title">🛣️ Manajemen Jalan</div>`;
data.jalan.forEach(j => {
var color = '#ef4444'; // default red
if(j.status_jalan === 'Nasional') color = '#ef4444';
else if(j.status_jalan === 'Provinsi') color = '#eab308';
else if(j.status_jalan === 'Kabupaten') color = '#22c55e';
if (j.status_jalan === 'Nasional') color = '#ef4444';
else if (j.status_jalan === 'Provinsi') color = '#eab308';
else if (j.status_jalan === 'Kabupaten') color = '#22c55e';
html += `<div class="card item-data" data-nama="${j.nama_jalan.toLowerCase()}">
<div style="display:flex; justify-content:space-between">
<span>
@@ -373,9 +373,9 @@ function renderMap(data) {
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${m.id}, 'masjid')">Hapus</button>
</div>`;
var faClass = 'fa-mosque';
if(m.jenis === 'Gereja') faClass = 'fa-church';
else if(m.jenis === 'Vihara') faClass = 'fa-vihara';
else if(m.jenis === 'Pura') faClass = 'fa-torii-gate';
if (m.jenis === 'Gereja') faClass = 'fa-church';
else if (m.jenis === 'Vihara') faClass = 'fa-vihara';
else if (m.jenis === 'Pura') faClass = 'fa-torii-gate';
// Buat custom marker bentuk map pin dengan icon sesuai jenis
var masjidIcon = L.divIcon({
@@ -408,7 +408,7 @@ function renderMap(data) {
});
L.marker([m.latitude, m.longitude], { icon: masjidIcon, draggable: true }).addTo(layerMasjid).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
.on('dragend', function (e) { updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
L.circle([m.latitude, m.longitude], {
radius: currentRadius, color: '#2563eb', fillOpacity: 0.1, weight: 1
}).addTo(layerMasjidRadius);
@@ -454,7 +454,7 @@ function renderMap(data) {
L.marker([p.latitude, p.longitude], {
icon: pelaporanIcon, draggable: true
}).addTo(layerPelaporan).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
.on('dragend', function (e) { updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
});
}
@@ -473,7 +473,7 @@ function renderMap(data) {
L.marker([s.latitude, s.longitude], {
icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }), draggable: true
}).addTo(targetLayer).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
.on('dragend', function (e) { updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
});
}
@@ -546,8 +546,8 @@ function renderMap(data) {
</div>
</div>`;
L.marker(pos, { icon: houseIcon, draggable: true })
.addTo(layerWarga).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
.addTo(layerWarga).bindPopup(popup)
.on('dragend', function (e) { updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
});
}
@@ -556,16 +556,16 @@ function renderMap(data) {
data.jalan.forEach(j => {
var coords = JSON.parse(j.koordinat);
var color = '#ef4444'; // default red
if(j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
else if(j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
else if(j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
if (j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
else if (j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
else if (j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
var popup = `<b>🛣️ ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} meter<br>
<div style="margin-top:10px; text-align:center;">
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('jalan', ${j.id})">Edit</button>
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${j.id}, 'jalan')">Hapus</button>
</div>`;
var polyline = L.polyline(coords, {color: color, weight: 6}).addTo(layerLines).bindPopup(popup);
var polyline = L.polyline(coords, { color: color, weight: 6 }).addTo(layerLines).bindPopup(popup);
polyline.db_id = j.id;
polyline.db_tipe = 'jalan';
drawnItems.addLayer(polyline);
@@ -579,7 +579,7 @@ function renderMap(data) {
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('parsil', ${p.id})">Edit</button>
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${p.id}, 'parsil')">Hapus</button>
</div>`;
var polygon = L.polygon(coords, {color: '#2563eb', fillOpacity: 0.4}).addTo(layerPolygons).bindPopup(popup);
var polygon = L.polygon(coords, { color: '#2563eb', fillOpacity: 0.4 }).addTo(layerPolygons).bindPopup(popup);
polygon.db_id = p.id;
polygon.db_tipe = 'parsil';
drawnItems.addLayer(polygon);
@@ -622,8 +622,8 @@ function simpanData() {
fd.append('status_hak', document.getElementById('status_hak').value);
fd.append('koordinat', document.getElementById('parsil_coords').value);
} else {
if(j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
Swal.fire({icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!'});
if (j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
Swal.fire({ icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!' });
return;
}
fd.append('lat', lat); fd.append('lng', lng);
@@ -651,15 +651,15 @@ function simpanData() {
}
}
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
fetch('../api/api.php', { method: 'POST', body: fd })
.then(res => res.json())
.then((res) => {
if (res.status === 'error') {
Swal.fire('Gagal!', res.message, 'error');
} else {
Swal.fire({icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false})
.then(() => location.reload());
Swal.fire({ icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false })
.then(() => location.reload());
}
});
}
@@ -670,7 +670,7 @@ function hapusData(id, tipe) {
showCancelButton: true, confirmButtonColor: '#ef4444', cancelButtonColor: '#94a3b8', confirmButtonText: 'Ya, Hapus!'
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
var fd = new FormData();
fd.append('action', 'hapus_data');
fd.append('id', id);
@@ -700,16 +700,16 @@ function batalEdit() {
function editData(tipe, id) {
var item = cachedData[tipe].find(x => x.id == id);
if(!item) return;
if (!item) return;
document.getElementById('edit_id').value = id;
document.getElementById('jenis').value = tipe;
toggleForm();
var panel = document.getElementById('panelInput');
if(panel) panel.classList.remove('collapsed');
if (panel) panel.classList.remove('collapsed');
if(tipe == 'warga') {
if (tipe == 'warga') {
document.getElementById('nama_kk').value = item.nama;
document.getElementById('jumlah_kk').value = item.jumlah_kk;
document.getElementById('tanggal_lahir').value = item.tanggal_lahir || '';
@@ -739,7 +739,7 @@ function editData(tipe, id) {
document.getElementById('parsil_coords').value = item.koordinat;
}
if(item.latitude && item.longitude) {
if (item.latitude && item.longitude) {
document.getElementById('lat').value = item.latitude;
document.getElementById('lng').value = item.longitude;
fokus(item.latitude, item.longitude);
+1
View File
@@ -1,4 +1,5 @@
<?php
session_set_cookie_params(['path' => '/']);
session_start();
$role = $_SESSION['role'] ?? null;
$is_logged_in = isset($_SESSION['login']);
+1
View File
@@ -1,4 +1,5 @@
<?php
session_set_cookie_params(['path' => '/']);
session_start();
require_once '../api/db.php';
+1
View File
@@ -1,4 +1,5 @@
<?php
session_set_cookie_params(['path' => '/']);
session_start();
session_unset();
session_destroy();
+1
View File
@@ -1,4 +1,5 @@
<?php
session_set_cookie_params(['path' => '/']);
session_start();
require_once '../api/db.php';
+46 -46
View File
@@ -37,7 +37,7 @@ var cachedData = null;
var drawControl = new L.Control.Draw({
draw: {
marker:false, circle:false, circlemarker:false,
marker: false, circle: false, circlemarker: false,
polyline: { shapeOptions: { color: 'blue', weight: 4 } },
polygon: { shapeOptions: { color: 'red' } },
rectangle: false
@@ -47,7 +47,7 @@ var drawControl = new L.Control.Draw({
map.addControl(drawControl);
// Locate Control
var locateBtn = L.control({position: 'topleft'});
var locateBtn = L.control({ position: 'topleft' });
locateBtn.onAdd = function (map) {
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
div.style.backgroundColor = 'white';
@@ -59,13 +59,13 @@ locateBtn.onAdd = function (map) {
div.style.justifyContent = 'center';
div.innerHTML = '<i class="fas fa-crosshairs" style="font-size:1.2rem; color:#2563eb;"></i>';
div.title = "Lokasi Anda Saat Ini";
div.onclick = function(){ map.locate({setView: true, maxZoom: 16}); }
div.onclick = function () { map.locate({ setView: true, maxZoom: 16 }); }
return div;
};
locateBtn.addTo(map);
map.on('locationfound', function(e) {
L.circleMarker(e.latlng, {radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1}).addTo(map).bindPopup("Lokasi Anda").openPopup();
map.on('locationfound', function (e) {
L.circleMarker(e.latlng, { radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1 }).addTo(map).bindPopup("Lokasi Anda").openPopup();
});
// Event Draw
@@ -103,7 +103,7 @@ map.on(L.Draw.Event.CREATED, function (e) {
map.on(L.Draw.Event.EDITED, function (e) {
var layers = e.layers;
layers.eachLayer(function (layer) {
if(layer.db_id && layer.db_tipe) {
if (layer.db_id && layer.db_tipe) {
var coords = (layer.db_tipe === 'parsil') ? layer.getLatLngs()[0] : layer.getLatLngs();
var fd = new FormData();
fd.append('action', 'update_koordinat');
@@ -111,7 +111,7 @@ map.on(L.Draw.Event.EDITED, function (e) {
fd.append('tipe', layer.db_tipe);
fd.append('koordinat', JSON.stringify(coords));
if(layer.db_tipe === 'jalan') {
if (layer.db_tipe === 'jalan') {
var length = 0;
for (var i = 0; i < coords.length - 1; i++) {
length += coords[i].distanceTo(coords[i + 1]);
@@ -121,13 +121,13 @@ map.on(L.Draw.Event.EDITED, function (e) {
fetch('../api/api.php', { method: 'POST', body: fd });
}
});
Swal.fire({icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false});
Swal.fire({ icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false });
});
map.on(L.Draw.Event.DELETED, function (e) {
var layers = e.layers;
layers.eachLayer(function (layer) {
if(layer.db_id && layer.db_tipe) {
if (layer.db_id && layer.db_tipe) {
var fd = new FormData();
fd.append('action', 'hapus_data');
fd.append('id', layer.db_id);
@@ -135,20 +135,20 @@ map.on(L.Draw.Event.DELETED, function (e) {
fetch('../api/api.php', { method: 'POST', body: fd });
}
});
Swal.fire({icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false});
Swal.fire({ icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false });
});
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('active'); }
function toggleRightPanel() {
var panel = document.getElementById('panelInput');
if(panel) panel.classList.toggle('collapsed');
if (panel) panel.classList.toggle('collapsed');
}
function filterData() {
var input = document.getElementById('searchInput').value.toLowerCase();
var cards = document.getElementsByClassName('item-data');
if(input.length > 0) document.getElementById('sidebar').classList.add('active');
if (input.length > 0) document.getElementById('sidebar').classList.add('active');
for (var i = 0; i < cards.length; i++) {
cards[i].style.display = cards[i].getAttribute('data-nama').includes(input) ? "" : "none";
}
@@ -157,7 +157,7 @@ function filterData() {
function changeRadius(v) {
currentRadius = parseInt(v);
document.getElementById('radiusVal').innerText = v;
if(cachedData) {
if (cachedData) {
renderMap(cachedData);
renderSidebar(cachedData);
}
@@ -186,8 +186,8 @@ function loadData(isPolling = false) {
prevReportCount = data.pelaporan.length;
var badge = document.getElementById('notifBadge');
if(badge) {
if(data.pelaporan.length > 0) {
if (badge) {
if (data.pelaporan.length > 0) {
badge.style.display = 'block';
badge.innerText = data.pelaporan.length;
} else {
@@ -211,7 +211,7 @@ function loadData(isPolling = false) {
// Auto-poll every 10 seconds
setInterval(() => {
// Only poll if not currently editing (edit_id is 0)
if(document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
if (document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
loadData(true);
}
}, 10000);
@@ -241,12 +241,12 @@ function renderSidebar(data) {
if (!window.dashboardType || window.dashboardType === 'sosial' || window.dashboardType === 'admin') {
// Pelaporan
html += `<div class="section-title" style="color:#ef4444">🚨 Laporan Darurat</div>`;
if(data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
if (data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
data.pelaporan.forEach(p => {
html += `<div class="card item-data" data-nama="${p.nama_pelapor.toLowerCase()} ${p.isi_laporan.toLowerCase()}">
<div style="display:flex; justify-content:space-between">
<span onclick="fokus(${p.latitude}, ${p.longitude})" style="cursor:pointer">
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0,40)}...</span>
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0, 40)}...</span>
</span>
<div>
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-bottom:5px;" onclick="editData('pelaporan', ${p.id})">Edit</button><br>
@@ -262,7 +262,7 @@ function renderSidebar(data) {
var pos = L.latLng(w.latitude, w.longitude);
var nearbyFacilities = data.masjid.map(m => {
return { nama: m.nama, distance: pos.distanceTo(L.latLng(m.latitude, m.longitude)) };
}).filter(f => f.distance <= currentRadius).sort((a,b) => a.distance - b.distance);
}).filter(f => f.distance <= currentRadius).sort((a, b) => a.distance - b.distance);
var facilityInfo = nearbyFacilities.length > 0 ? `<br><small style="color:#16a34a"><i class="fas fa-check-circle"></i> Jangkauan: ${nearbyFacilities[0].nama} (${Math.round(nearbyFacilities[0].distance)}m)</small>` : `<br><small style="color:#ef4444"><i class="fas fa-exclamation-triangle"></i> Jauh dari fasilitas / bantuan</small>`;
@@ -324,9 +324,9 @@ function renderSidebar(data) {
html += `<div class="section-title">🛣️ Manajemen Jalan</div>`;
data.jalan.forEach(j => {
var color = '#ef4444'; // default red
if(j.status_jalan === 'Nasional') color = '#ef4444';
else if(j.status_jalan === 'Provinsi') color = '#eab308';
else if(j.status_jalan === 'Kabupaten') color = '#22c55e';
if (j.status_jalan === 'Nasional') color = '#ef4444';
else if (j.status_jalan === 'Provinsi') color = '#eab308';
else if (j.status_jalan === 'Kabupaten') color = '#22c55e';
html += `<div class="card item-data" data-nama="${j.nama_jalan.toLowerCase()}">
<div style="display:flex; justify-content:space-between">
<span>
@@ -384,9 +384,9 @@ function renderMap(data) {
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${m.id}, 'masjid')">Hapus</button>
</div>`;
var faClass = 'fa-mosque';
if(m.jenis === 'Gereja') faClass = 'fa-church';
else if(m.jenis === 'Vihara') faClass = 'fa-vihara';
else if(m.jenis === 'Pura') faClass = 'fa-torii-gate';
if (m.jenis === 'Gereja') faClass = 'fa-church';
else if (m.jenis === 'Vihara') faClass = 'fa-vihara';
else if (m.jenis === 'Pura') faClass = 'fa-torii-gate';
// Buat custom marker bentuk map pin dengan icon sesuai jenis
var masjidIcon = L.divIcon({
@@ -419,7 +419,7 @@ function renderMap(data) {
});
L.marker([m.latitude, m.longitude], { icon: masjidIcon, draggable: true }).addTo(layerMasjid).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
.on('dragend', function (e) { updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
L.circle([m.latitude, m.longitude], {
radius: currentRadius, color: '#2563eb', fillOpacity: 0.1, weight: 1
}).addTo(layerMasjidRadius);
@@ -465,7 +465,7 @@ function renderMap(data) {
L.marker([p.latitude, p.longitude], {
icon: pelaporanIcon, draggable: true
}).addTo(layerPelaporan).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
.on('dragend', function (e) { updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
});
}
@@ -484,7 +484,7 @@ function renderMap(data) {
L.marker([s.latitude, s.longitude], {
icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }), draggable: true
}).addTo(targetLayer).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
.on('dragend', function (e) { updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
});
}
@@ -494,7 +494,7 @@ function renderMap(data) {
var pos = L.latLng(w.latitude, w.longitude);
var nearbyFacilities = data.masjid.map(m => {
return { nama: m.nama, distance: pos.distanceTo(L.latLng(m.latitude, m.longitude)) };
}).filter(f => f.distance <= currentRadius).sort((a,b) => a.distance - b.distance);
}).filter(f => f.distance <= currentRadius).sort((a, b) => a.distance - b.distance);
var isCovered = nearbyFacilities.length > 0;
var nearestName = isCovered ? nearbyFacilities[0].nama : '-';
var nearestDist = isCovered ? Math.round(nearbyFacilities[0].distance) + 'm' : '-';
@@ -563,8 +563,8 @@ function renderMap(data) {
</div>
</div>`;
L.marker(pos, { icon: houseIcon, draggable: true })
.addTo(layerWarga).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
.addTo(layerWarga).bindPopup(popup)
.on('dragend', function (e) { updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
});
}
@@ -573,16 +573,16 @@ function renderMap(data) {
data.jalan.forEach(j => {
var coords = JSON.parse(j.koordinat);
var color = '#ef4444'; // default red
if(j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
else if(j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
else if(j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
if (j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
else if (j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
else if (j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
var popup = `<b>🛣️ ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} meter<br>
<div style="margin-top:10px; text-align:center;">
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('jalan', ${j.id})">Edit</button>
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${j.id}, 'jalan')">Hapus</button>
</div>`;
var polyline = L.polyline(coords, {color: color, weight: 6}).addTo(layerLines).bindPopup(popup);
var polyline = L.polyline(coords, { color: color, weight: 6 }).addTo(layerLines).bindPopup(popup);
polyline.db_id = j.id;
polyline.db_tipe = 'jalan';
drawnItems.addLayer(polyline);
@@ -596,7 +596,7 @@ function renderMap(data) {
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('parsil', ${p.id})">Edit</button>
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${p.id}, 'parsil')">Hapus</button>
</div>`;
var polygon = L.polygon(coords, {color: '#2563eb', fillOpacity: 0.4}).addTo(layerPolygons).bindPopup(popup);
var polygon = L.polygon(coords, { color: '#2563eb', fillOpacity: 0.4 }).addTo(layerPolygons).bindPopup(popup);
polygon.db_id = p.id;
polygon.db_tipe = 'parsil';
drawnItems.addLayer(polygon);
@@ -639,8 +639,8 @@ function simpanData() {
fd.append('status_hak', document.getElementById('status_hak').value);
fd.append('koordinat', document.getElementById('parsil_coords').value);
} else {
if(j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
Swal.fire({icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!'});
if (j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
Swal.fire({ icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!' });
return;
}
fd.append('lat', lat); fd.append('lng', lng);
@@ -669,15 +669,15 @@ function simpanData() {
}
}
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
fetch('../api/api.php', { method: 'POST', body: fd })
.then(res => res.json())
.then((res) => {
if (res.status === 'error') {
Swal.fire('Gagal!', res.message, 'error');
} else {
Swal.fire({icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false})
.then(() => location.reload());
Swal.fire({ icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false })
.then(() => location.reload());
}
});
}
@@ -688,7 +688,7 @@ function hapusData(id, tipe) {
showCancelButton: true, confirmButtonColor: '#ef4444', cancelButtonColor: '#94a3b8', confirmButtonText: 'Ya, Hapus!'
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
var fd = new FormData();
fd.append('action', 'hapus_data');
fd.append('id', id);
@@ -718,16 +718,16 @@ function batalEdit() {
function editData(tipe, id) {
var item = cachedData[tipe].find(x => x.id == id);
if(!item) return;
if (!item) return;
document.getElementById('edit_id').value = id;
document.getElementById('jenis').value = tipe;
toggleForm();
var panel = document.getElementById('panelInput');
if(panel) panel.classList.remove('collapsed');
if (panel) panel.classList.remove('collapsed');
if(tipe == 'warga') {
if (tipe == 'warga') {
document.getElementById('nama_kk').value = item.nama;
document.getElementById('jumlah_kk').value = item.jumlah_kk;
document.getElementById('tanggal_lahir').value = item.tanggal_lahir || '';
@@ -758,7 +758,7 @@ function editData(tipe, id) {
document.getElementById('parsil_coords').value = item.koordinat;
}
if(item.latitude && item.longitude) {
if (item.latitude && item.longitude) {
document.getElementById('lat').value = item.latitude;
document.getElementById('lng').value = item.longitude;
fokus(item.latitude, item.longitude);
+1
View File
@@ -1,4 +1,5 @@
<?php
session_set_cookie_params(['path' => '/']);
session_start();
require_once '../api/db.php';
+44 -44
View File
@@ -37,7 +37,7 @@ var cachedData = null;
var drawControl = new L.Control.Draw({
draw: {
marker:false, circle:false, circlemarker:false,
marker: false, circle: false, circlemarker: false,
polyline: { shapeOptions: { color: 'blue', weight: 4 } },
polygon: { shapeOptions: { color: 'red' } },
rectangle: false
@@ -47,7 +47,7 @@ var drawControl = new L.Control.Draw({
map.addControl(drawControl);
// Locate Control
var locateBtn = L.control({position: 'topleft'});
var locateBtn = L.control({ position: 'topleft' });
locateBtn.onAdd = function (map) {
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
div.style.backgroundColor = 'white';
@@ -59,13 +59,13 @@ locateBtn.onAdd = function (map) {
div.style.justifyContent = 'center';
div.innerHTML = '<i class="fas fa-crosshairs" style="font-size:1.2rem; color:#2563eb;"></i>';
div.title = "Lokasi Anda Saat Ini";
div.onclick = function(){ map.locate({setView: true, maxZoom: 16}); }
div.onclick = function () { map.locate({ setView: true, maxZoom: 16 }); }
return div;
};
locateBtn.addTo(map);
map.on('locationfound', function(e) {
L.circleMarker(e.latlng, {radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1}).addTo(map).bindPopup("Lokasi Anda").openPopup();
map.on('locationfound', function (e) {
L.circleMarker(e.latlng, { radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1 }).addTo(map).bindPopup("Lokasi Anda").openPopup();
});
// Event Draw
@@ -103,7 +103,7 @@ map.on(L.Draw.Event.CREATED, function (e) {
map.on(L.Draw.Event.EDITED, function (e) {
var layers = e.layers;
layers.eachLayer(function (layer) {
if(layer.db_id && layer.db_tipe) {
if (layer.db_id && layer.db_tipe) {
var coords = (layer.db_tipe === 'parsil') ? layer.getLatLngs()[0] : layer.getLatLngs();
var fd = new FormData();
fd.append('action', 'update_koordinat');
@@ -111,7 +111,7 @@ map.on(L.Draw.Event.EDITED, function (e) {
fd.append('tipe', layer.db_tipe);
fd.append('koordinat', JSON.stringify(coords));
if(layer.db_tipe === 'jalan') {
if (layer.db_tipe === 'jalan') {
var length = 0;
for (var i = 0; i < coords.length - 1; i++) {
length += coords[i].distanceTo(coords[i + 1]);
@@ -121,13 +121,13 @@ map.on(L.Draw.Event.EDITED, function (e) {
fetch('../api/api.php', { method: 'POST', body: fd });
}
});
Swal.fire({icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false});
Swal.fire({ icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false });
});
map.on(L.Draw.Event.DELETED, function (e) {
var layers = e.layers;
layers.eachLayer(function (layer) {
if(layer.db_id && layer.db_tipe) {
if (layer.db_id && layer.db_tipe) {
var fd = new FormData();
fd.append('action', 'hapus_data');
fd.append('id', layer.db_id);
@@ -135,20 +135,20 @@ map.on(L.Draw.Event.DELETED, function (e) {
fetch('../api/api.php', { method: 'POST', body: fd });
}
});
Swal.fire({icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false});
Swal.fire({ icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false });
});
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('active'); }
function toggleRightPanel() {
var panel = document.getElementById('panelInput');
if(panel) panel.classList.toggle('collapsed');
if (panel) panel.classList.toggle('collapsed');
}
function filterData() {
var input = document.getElementById('searchInput').value.toLowerCase();
var cards = document.getElementsByClassName('item-data');
if(input.length > 0) document.getElementById('sidebar').classList.add('active');
if (input.length > 0) document.getElementById('sidebar').classList.add('active');
for (var i = 0; i < cards.length; i++) {
cards[i].style.display = cards[i].getAttribute('data-nama').includes(input) ? "" : "none";
}
@@ -157,7 +157,7 @@ function filterData() {
function changeRadius(v) {
currentRadius = parseInt(v);
document.getElementById('radiusVal').innerText = v;
if(cachedData) renderMap(cachedData);
if (cachedData) renderMap(cachedData);
}
var prevReportCount = -1;
@@ -183,8 +183,8 @@ function loadData(isPolling = false) {
prevReportCount = data.pelaporan.length;
var badge = document.getElementById('notifBadge');
if(badge) {
if(data.pelaporan.length > 0) {
if (badge) {
if (data.pelaporan.length > 0) {
badge.style.display = 'block';
badge.innerText = data.pelaporan.length;
} else {
@@ -208,7 +208,7 @@ function loadData(isPolling = false) {
// Auto-poll every 10 seconds
setInterval(() => {
// Only poll if not currently editing (edit_id is 0)
if(document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
if (document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
loadData(true);
}
}, 10000);
@@ -238,12 +238,12 @@ function renderSidebar(data) {
if (!window.dashboardType || window.dashboardType === 'sosial' || window.dashboardType === 'admin') {
// Pelaporan
html += `<div class="section-title" style="color:#ef4444">🚨 Laporan Darurat</div>`;
if(data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
if (data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
data.pelaporan.forEach(p => {
html += `<div class="card item-data" data-nama="${p.nama_pelapor.toLowerCase()} ${p.isi_laporan.toLowerCase()}">
<div style="display:flex; justify-content:space-between">
<span onclick="fokus(${p.latitude}, ${p.longitude})" style="cursor:pointer">
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0,40)}...</span>
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0, 40)}...</span>
</span>
<div>
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-bottom:5px;" onclick="editData('pelaporan', ${p.id})">Edit</button><br>
@@ -313,9 +313,9 @@ function renderSidebar(data) {
html += `<div class="section-title">🛣️ Manajemen Jalan</div>`;
data.jalan.forEach(j => {
var color = '#ef4444'; // default red
if(j.status_jalan === 'Nasional') color = '#ef4444';
else if(j.status_jalan === 'Provinsi') color = '#eab308';
else if(j.status_jalan === 'Kabupaten') color = '#22c55e';
if (j.status_jalan === 'Nasional') color = '#ef4444';
else if (j.status_jalan === 'Provinsi') color = '#eab308';
else if (j.status_jalan === 'Kabupaten') color = '#22c55e';
html += `<div class="card item-data" data-nama="${j.nama_jalan.toLowerCase()}">
<div style="display:flex; justify-content:space-between">
<span>
@@ -373,9 +373,9 @@ function renderMap(data) {
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${m.id}, 'masjid')">Hapus</button>
</div>`;
var faClass = 'fa-mosque';
if(m.jenis === 'Gereja') faClass = 'fa-church';
else if(m.jenis === 'Vihara') faClass = 'fa-vihara';
else if(m.jenis === 'Pura') faClass = 'fa-torii-gate';
if (m.jenis === 'Gereja') faClass = 'fa-church';
else if (m.jenis === 'Vihara') faClass = 'fa-vihara';
else if (m.jenis === 'Pura') faClass = 'fa-torii-gate';
// Buat custom marker bentuk map pin dengan icon sesuai jenis
var masjidIcon = L.divIcon({
@@ -408,7 +408,7 @@ function renderMap(data) {
});
L.marker([m.latitude, m.longitude], { icon: masjidIcon, draggable: true }).addTo(layerMasjid).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
.on('dragend', function (e) { updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
L.circle([m.latitude, m.longitude], {
radius: currentRadius, color: '#2563eb', fillOpacity: 0.1, weight: 1
}).addTo(layerMasjidRadius);
@@ -454,7 +454,7 @@ function renderMap(data) {
L.marker([p.latitude, p.longitude], {
icon: pelaporanIcon, draggable: true
}).addTo(layerPelaporan).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
.on('dragend', function (e) { updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
});
}
@@ -473,7 +473,7 @@ function renderMap(data) {
L.marker([s.latitude, s.longitude], {
icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }), draggable: true
}).addTo(targetLayer).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
.on('dragend', function (e) { updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
});
}
@@ -546,8 +546,8 @@ function renderMap(data) {
</div>
</div>`;
L.marker(pos, { icon: houseIcon, draggable: true })
.addTo(layerWarga).bindPopup(popup)
.on('dragend', function(e){ updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
.addTo(layerWarga).bindPopup(popup)
.on('dragend', function (e) { updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
});
}
@@ -556,16 +556,16 @@ function renderMap(data) {
data.jalan.forEach(j => {
var coords = JSON.parse(j.koordinat);
var color = '#ef4444'; // default red
if(j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
else if(j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
else if(j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
if (j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
else if (j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
else if (j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
var popup = `<b>🛣️ ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} meter<br>
<div style="margin-top:10px; text-align:center;">
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('jalan', ${j.id})">Edit</button>
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${j.id}, 'jalan')">Hapus</button>
</div>`;
var polyline = L.polyline(coords, {color: color, weight: 6}).addTo(layerLines).bindPopup(popup);
var polyline = L.polyline(coords, { color: color, weight: 6 }).addTo(layerLines).bindPopup(popup);
polyline.db_id = j.id;
polyline.db_tipe = 'jalan';
drawnItems.addLayer(polyline);
@@ -579,7 +579,7 @@ function renderMap(data) {
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('parsil', ${p.id})">Edit</button>
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${p.id}, 'parsil')">Hapus</button>
</div>`;
var polygon = L.polygon(coords, {color: '#2563eb', fillOpacity: 0.4}).addTo(layerPolygons).bindPopup(popup);
var polygon = L.polygon(coords, { color: '#2563eb', fillOpacity: 0.4 }).addTo(layerPolygons).bindPopup(popup);
polygon.db_id = p.id;
polygon.db_tipe = 'parsil';
drawnItems.addLayer(polygon);
@@ -622,8 +622,8 @@ function simpanData() {
fd.append('status_hak', document.getElementById('status_hak').value);
fd.append('koordinat', document.getElementById('parsil_coords').value);
} else {
if(j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
Swal.fire({icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!'});
if (j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
Swal.fire({ icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!' });
return;
}
fd.append('lat', lat); fd.append('lng', lng);
@@ -651,15 +651,15 @@ function simpanData() {
}
}
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
fetch('../api/api.php', { method: 'POST', body: fd })
.then(res => res.json())
.then((res) => {
if (res.status === 'error') {
Swal.fire('Gagal!', res.message, 'error');
} else {
Swal.fire({icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false})
.then(() => location.reload());
Swal.fire({ icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false })
.then(() => location.reload());
}
});
}
@@ -670,7 +670,7 @@ function hapusData(id, tipe) {
showCancelButton: true, confirmButtonColor: '#ef4444', cancelButtonColor: '#94a3b8', confirmButtonText: 'Ya, Hapus!'
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
var fd = new FormData();
fd.append('action', 'hapus_data');
fd.append('id', id);
@@ -700,16 +700,16 @@ function batalEdit() {
function editData(tipe, id) {
var item = cachedData[tipe].find(x => x.id == id);
if(!item) return;
if (!item) return;
document.getElementById('edit_id').value = id;
document.getElementById('jenis').value = tipe;
toggleForm();
var panel = document.getElementById('panelInput');
if(panel) panel.classList.remove('collapsed');
if (panel) panel.classList.remove('collapsed');
if(tipe == 'warga') {
if (tipe == 'warga') {
document.getElementById('nama_kk').value = item.nama;
document.getElementById('jumlah_kk').value = item.jumlah_kk;
document.getElementById('tanggal_lahir').value = item.tanggal_lahir || '';
@@ -739,7 +739,7 @@ function editData(tipe, id) {
document.getElementById('parsil_coords').value = item.koordinat;
}
if(item.latitude && item.longitude) {
if (item.latitude && item.longitude) {
document.getElementById('lat').value = item.latitude;
document.getElementById('lng').value = item.longitude;
fokus(item.latitude, item.longitude);