diff --git a/api/log_bantuan/create.php b/api/log_bantuan/create.php new file mode 100644 index 0000000..2abdc03 --- /dev/null +++ b/api/log_bantuan/create.php @@ -0,0 +1,27 @@ + 'error', 'message' => 'Data tidak lengkap']); + exit; +} + +$sql = "INSERT INTO log_bantuan (miskin_id, ibadah_id, tipe_bantuan, tanggal, keterangan) VALUES (?, ?, ?, ?, ?)"; +$stmt = $conn->prepare($sql); +$stmt->bind_param('iisss', $miskin_id, $ibadah_id, $tipe_bantuan, $tanggal, $keterangan); + +if ($stmt->execute()) { + echo json_encode(['status' => 'success', 'id' => $stmt->insert_id]); +} else { + echo json_encode(['status' => 'error', 'message' => $conn->error]); +} +$conn->close(); diff --git a/api/log_bantuan/read.php b/api/log_bantuan/read.php new file mode 100644 index 0000000..4cbc5c2 --- /dev/null +++ b/api/log_bantuan/read.php @@ -0,0 +1,37 @@ + 'error', 'message' => 'miskin_id diperlukan']); + exit; +} + +$sql = " + SELECT + lb.id, + lb.tipe_bantuan, + lb.tanggal, + lb.keterangan, + ri.nama AS nama_ibadah, + ri.jenis AS jenis_ibadah + FROM log_bantuan lb + JOIN rumah_ibadah ri ON ri.id = lb.ibadah_id + WHERE lb.miskin_id = ? + ORDER BY lb.tanggal DESC, lb.id DESC +"; + +$stmt = $conn->prepare($sql); +$stmt->bind_param('i', $miskin_id); +$stmt->execute(); +$result = $stmt->get_result(); + +$data = []; +while ($row = $result->fetch_assoc()) { + $data[] = $row; +} + +echo json_encode(['status' => 'success', 'data' => $data]); +$conn->close(); diff --git a/api/penduduk_miskin/create.php b/api/penduduk_miskin/create.php index 0e05e2f..c5a2945 100644 --- a/api/penduduk_miskin/create.php +++ b/api/penduduk_miskin/create.php @@ -4,15 +4,17 @@ include_once '../db_connect.php'; $data = json_decode(file_get_contents("php://input")); -if(!empty($data->lat) && !empty($data->lng)) { - $nama = $conn->real_escape_string($data->nama ?? ''); - $kategori = $conn->real_escape_string($data->kategori_bantuan ?? 'Makan'); - $lat = (float)$data->lat; - $lng = (float)$data->lng; +if (!empty($data->lat) && !empty($data->lng)) { + $nama = $conn->real_escape_string($data->nama ?? ''); + $kategori = $conn->real_escape_string($data->kategori_bantuan ?? 'Makan'); + $jumlah_jiwa = (int)($data->jumlah_jiwa ?? 1); + $lat = (float)$data->lat; + $lng = (float)$data->lng; - $query = "INSERT INTO penduduk_miskin (nama, kategori_bantuan, lat, lng) VALUES ('$nama', '$kategori', $lat, $lng)"; + $query = "INSERT INTO penduduk_miskin (nama, kategori_bantuan, jumlah_jiwa, lat, lng) + VALUES ('$nama', '$kategori', $jumlah_jiwa, $lat, $lng)"; - if($conn->query($query)) { + if ($conn->query($query)) { echo json_encode(["status" => "success", "id" => $conn->insert_id, "message" => "Berhasil ditambahkan."]); } else { echo json_encode(["status" => "error", "message" => "Gagal: " . $conn->error]); diff --git a/api/penduduk_miskin/update.php b/api/penduduk_miskin/update.php index ffa4d9f..2d05a2d 100644 --- a/api/penduduk_miskin/update.php +++ b/api/penduduk_miskin/update.php @@ -4,16 +4,19 @@ include_once '../db_connect.php'; $data = json_decode(file_get_contents("php://input")); -if(!empty($data->id)) { - $id = (int)$data->id; - $nama = $conn->real_escape_string($data->nama ?? ''); - $kategori = $conn->real_escape_string($data->kategori_bantuan ?? 'Makan'); - $lat = (float)$data->lat; - $lng = (float)$data->lng; +if (!empty($data->id)) { + $id = (int)$data->id; + $nama = $conn->real_escape_string($data->nama ?? ''); + $kategori = $conn->real_escape_string($data->kategori_bantuan ?? 'Makan'); + $jumlah_jiwa = (int)($data->jumlah_jiwa ?? 1); + $lat = (float)$data->lat; + $lng = (float)$data->lng; - $query = "UPDATE penduduk_miskin SET nama='$nama', kategori_bantuan='$kategori', lat=$lat, lng=$lng WHERE id=$id"; + $query = "UPDATE penduduk_miskin + SET nama='$nama', kategori_bantuan='$kategori', jumlah_jiwa=$jumlah_jiwa, lat=$lat, lng=$lng + WHERE id=$id"; - if($conn->query($query)) { + if ($conn->query($query)) { echo json_encode(["status" => "success", "message" => "Update berhasil."]); } else { echo json_encode(["status" => "error", "message" => "Gagal update: " . $conn->error]); diff --git a/api/rumah_ibadah/create.php b/api/rumah_ibadah/create.php index 307c6d1..4f77d6a 100644 --- a/api/rumah_ibadah/create.php +++ b/api/rumah_ibadah/create.php @@ -4,16 +4,18 @@ include_once '../db_connect.php'; $data = json_decode(file_get_contents("php://input")); -if(!empty($data->lat) && !empty($data->lng)) { - $nama = $conn->real_escape_string($data->nama ?? ''); +if (!empty($data->lat) && !empty($data->lng)) { + $nama = $conn->real_escape_string($data->nama ?? ''); + $jenis = $conn->real_escape_string($data->jenis ?? 'Masjid'); $alamat = $conn->real_escape_string($data->alamat ?? ''); - $radius = (float)($data->radius ?? 100); - $lat = (float)$data->lat; - $lng = (float)$data->lng; + $radius = (float)($data->radius ?? 500); + $lat = (float)$data->lat; + $lng = (float)$data->lng; - $query = "INSERT INTO rumah_ibadah (nama, alamat, radius, lat, lng) VALUES ('$nama', '$alamat', $radius, $lat, $lng)"; + $query = "INSERT INTO rumah_ibadah (nama, jenis, alamat, radius, lat, lng) + VALUES ('$nama', '$jenis', '$alamat', $radius, $lat, $lng)"; - if($conn->query($query)) { + if ($conn->query($query)) { echo json_encode(["status" => "success", "id" => $conn->insert_id, "message" => "Rumah Ibadah berhasil ditambahkan."]); } else { echo json_encode(["status" => "error", "message" => "Gagal menambahkan: " . $conn->error]); diff --git a/api/rumah_ibadah/update.php b/api/rumah_ibadah/update.php index 1b19cde..a40abb9 100644 --- a/api/rumah_ibadah/update.php +++ b/api/rumah_ibadah/update.php @@ -4,17 +4,20 @@ include_once '../db_connect.php'; $data = json_decode(file_get_contents("php://input")); -if(!empty($data->id)) { - $id = (int)$data->id; - $nama = $conn->real_escape_string($data->nama ?? ''); +if (!empty($data->id)) { + $id = (int)$data->id; + $nama = $conn->real_escape_string($data->nama ?? ''); + $jenis = $conn->real_escape_string($data->jenis ?? 'Masjid'); $alamat = $conn->real_escape_string($data->alamat ?? ''); - $radius = (float)($data->radius ?? 100); - $lat = (float)$data->lat; - $lng = (float)$data->lng; + $radius = (float)($data->radius ?? 500); + $lat = (float)$data->lat; + $lng = (float)$data->lng; - $query = "UPDATE rumah_ibadah SET nama='$nama', alamat='$alamat', radius=$radius, lat=$lat, lng=$lng WHERE id=$id"; + $query = "UPDATE rumah_ibadah + SET nama='$nama', jenis='$jenis', alamat='$alamat', radius=$radius, lat=$lat, lng=$lng + WHERE id=$id"; - if($conn->query($query)) { + if ($conn->query($query)) { echo json_encode(["status" => "success", "message" => "Update berhasil."]); } else { echo json_encode(["status" => "error", "message" => "Gagal update: " . $conn->error]); diff --git a/assets/css/style.css b/assets/css/style.css index f28612a..d7d40e7 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -15,7 +15,7 @@ body, html { #map { width: 100vw; height: 100vh; - z-index: 1; /* Di bawah UI element */ + z-index: 1; } /* Custom UI Container over Map */ @@ -75,7 +75,7 @@ body, html { display: flex; align-items: center; justify-content: center; - visibility: hidden; /* Muncul jika ada input */ + visibility: hidden; } .search-clear:hover { @@ -115,9 +115,10 @@ body, html { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); padding: 15px; width: 250px; - display: none; /* Default tertutup */ + display: none; } + .custom-layer-panel h3 { margin-bottom: 10px; font-size: 16px; @@ -133,6 +134,436 @@ body, html { font-size: 14px; } +/* ===== Sidebar Toggle Button ===== */ +.sidebar-toggle-btn { + position: absolute; + left: 20px; + top: 90px; + z-index: 1001; + width: 36px; + height: 36px; + background: white; + border: none; + border-radius: 10px; + box-shadow: 0 3px 10px rgba(0,0,0,0.15); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + color: #6366f1; + font-size: 13px; + transition: all 0.2s; +} + +.sidebar-toggle-btn:hover { + background: #6366f1; + color: white; + box-shadow: 0 4px 14px rgba(99,102,241,0.4); +} + +.sidebar-toggle-btn.open { + background: #6366f1; + color: white; +} + +/* ===== Left Sidebar ===== */ +.left-sidebar { + position: absolute; + left: 20px; + top: 136px; /* di bawah toggle button */ + z-index: 1000; + display: flex; + flex-direction: column; + gap: 8px; +} + +.sidebar-btn { + width: 60px; + height: 60px; + background: white; + border: none; + border-radius: 12px; + box-shadow: 0 4px 12px rgba(0,0,0,0.12); + cursor: pointer; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 2px; + transition: all 0.2s ease; + padding: 6px 4px; +} + +.sidebar-btn:hover { + transform: translateX(3px); + box-shadow: 0 6px 18px rgba(0,0,0,0.18); + background: #f8f9fa; +} + +.sidebar-btn.active { + background: linear-gradient(135deg, #6366f1, #4f46e5); + color: white; + box-shadow: 0 6px 18px rgba(99,102,241,0.4); + transform: translateX(4px); +} + +.sidebar-emoji { + font-size: 22px; + line-height: 1; +} + +.sidebar-label { + font-size: 9px; + font-weight: 600; + letter-spacing: 0.3px; + color: #555; + text-transform: uppercase; +} + +.sidebar-btn.active .sidebar-label { + color: rgba(255,255,255,0.85); +} + +/* ===== Right Panel ===== */ +.right-panel { + position: absolute; + top: 0; + right: 0; + bottom: 0; + width: 320px; + background: #f8f9fb; + z-index: 999; + box-shadow: -4px 0 20px rgba(0,0,0,0.12); + display: flex; + flex-direction: column; + transform: translateX(100%); + transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); + /* shift layer control when panel open */ +} + +.right-panel.open { + transform: translateX(0); +} + +.right-panel-header { + padding: 16px 16px 12px; + background: white; + border-bottom: 1px solid #eee; + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; + padding-top: 26px; +} + +.right-panel-header h3 { + font-size: 15px; + font-weight: 700; + color: #1e1e2e; +} + +.right-panel-close { + width: 30px; + height: 30px; + border: none; + background: #f3f4f6; + border-radius: 8px; + cursor: pointer; + color: #555; + display: flex; + align-items: center; + justify-content: center; + font-size: 13px; + transition: background 0.2s; +} + +.right-panel-close:hover { + background: #e5e7eb; + color: #333; +} + +.right-panel-actions { + padding: 12px 14px; + background: white; + border-bottom: 1px solid #eee; + display: flex; + gap: 8px; + flex-shrink: 0; +} + +.right-panel-actions button { + flex: 1; + padding: 9px 10px; + border: none; + border-radius: 8px; + font-size: 12px; + font-weight: 600; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + transition: all 0.2s; +} + +.btn-panel-add { + background: linear-gradient(135deg, #6366f1, #4f46e5); + color: white; + box-shadow: 0 3px 10px rgba(99,102,241,0.3); +} + +.btn-panel-add:hover { + box-shadow: 0 5px 14px rgba(99,102,241,0.45); + transform: translateY(-1px); +} + +.btn-panel-import { + background: #f0fdf4; + color: #16a34a; + border: 1px solid #bbf7d0 !important; +} + +.btn-panel-import:hover { + background: #dcfce7; +} + +.right-panel-body { + flex: 1; + overflow-y: auto; + padding: 12px; + display: flex; + flex-direction: column; + gap: 8px; +} + +/* Panel Section Heading */ +.panel-section-title { + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.5px; + color: #9ca3af; + padding: 4px 2px 6px; + border-bottom: 1px solid #e5e7eb; + margin-top: 4px; +} + +/* Panel Empty State */ +.panel-empty { + text-align: center; + color: #aaa; + font-size: 13px; + padding: 40px 10px; +} + +/* ===== Data Card ===== */ +.data-card { + background: white; + border-radius: 12px; + padding: 12px 12px 10px; + box-shadow: 0 1px 4px rgba(0,0,0,0.07); + transition: box-shadow 0.2s; + cursor: pointer; +} + +.data-card:hover { + box-shadow: 0 3px 12px rgba(0,0,0,0.12); +} + +.data-card-main { + display: flex; + align-items: center; + gap: 10px; +} + +.data-card-icon { + width: 40px; + height: 40px; + border-radius: 10px; + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + flex-shrink: 0; +} + +.card-icon-spbu { background: #f0fdf4; } +.card-icon-jalan { background: #eff6ff; } +.card-icon-parsil { background: #fefce8; } +.card-icon-ibadah { background: #fff7ed; } +.card-icon-miskin-out { background: #f0fdf4; } +.card-icon-miskin-in { background: #fef2f2; } + +.data-card-info { + flex: 1; + min-width: 0; +} + +.data-card-name { + font-size: 13px; + font-weight: 600; + color: #1e1e2e; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.data-card-sub { + font-size: 11px; + color: #6b7280; + margin-top: 2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.data-card-badge { + font-size: 10px; + font-weight: 600; + padding: 2px 7px; + border-radius: 99px; + margin-top: 4px; + display: inline-block; +} + +.badge-green { background: #dcfce7; color: #16a34a; } +.badge-red { background: #fee2e2; color: #dc2626; } +.badge-blue { background: #dbeafe; color: #2563eb; } +.badge-orange { background: #ffedd5; color: #ea580c; } +.badge-yellow { background: #fef9c3; color: #ca8a04; } + +.data-card-actions { + display: flex; + gap: 6px; + flex-shrink: 0; + align-items: center; +} + +.btn-card-action { + width: 30px; + height: 30px; + border: none; + border-radius: 7px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: 12px; + transition: all 0.15s; +} + +.btn-card-edit { + background: #eff6ff; + color: #3b82f6; +} + +.btn-card-edit:hover { + background: #3b82f6; + color: white; +} + +.btn-card-delete { + background: #fef2f2; + color: #ef4444; +} + +.btn-card-delete:hover { + background: #ef4444; + color: white; +} + +/* Expandable card (miskin) */ +.data-card-expand { + overflow: hidden; + max-height: 0; + transition: max-height 0.3s ease, padding 0.2s; + border-top: 0px solid #f3f4f6; +} + +.data-card.expanded .data-card-expand { + max-height: 400px; + border-top: 1px solid #f3f4f6; + margin-top: 10px; + padding-top: 10px; +} + +.expand-row { + display: flex; + justify-content: space-between; + font-size: 12px; + color: #6b7280; + padding: 3px 0; +} + +.expand-row span:first-child { + font-weight: 500; + color: #374151; +} + +.btn-log-bantuan { + margin-top: 10px; + width: 100%; + padding: 8px; + background: linear-gradient(135deg, #6366f1, #4f46e5); + color: white; + border: none; + border-radius: 8px; + font-size: 12px; + font-weight: 600; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + gap: 6px; + transition: all 0.2s; +} + +.btn-log-bantuan:hover { + box-shadow: 0 4px 12px rgba(99,102,241,0.4); +} + +/* Log Bantuan Item */ +.log-item { + background: #f8f9fb; + border-radius: 8px; + padding: 10px 12px; + display: flex; + gap: 10px; + align-items: flex-start; +} + +.log-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: #6366f1; + flex-shrink: 0; + margin-top: 5px; +} + +.log-info { + flex: 1; +} + +.log-type { + font-size: 12px; + font-weight: 600; + color: #1e1e2e; +} + +.log-meta { + font-size: 11px; + color: #9ca3af; + margin-top: 2px; +} + +.log-keterangan { + font-size: 11px; + color: #6b7280; + margin-top: 3px; + font-style: italic; +} + /* Popup Form */ .popup-form { display: flex; @@ -178,51 +609,6 @@ body, html { opacity: 0.9; } -/* Action Menu (Kiri) */ -.action-menu { - position: absolute; - z-index: 1000; - background: transparent; - box-shadow: none; - padding: 0; - display: flex; - flex-direction: column; - gap: 10px; - width: 200px; -} - -.action-menu button { - padding: 10px 15px; - background-color: white; - border: none; - border-radius: 25px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - cursor: pointer; - text-align: left; - font-size: 13px; - font-weight: 500; - transition: all 0.2s; - display: flex; - align-items: center; - gap: 8px; -} - -.action-menu button i { - width: 16px; - text-align: center; -} - -.action-menu button:hover { - background-color: #f8f9fa; - transform: translateX(5px); -} - -.action-menu button.active { - background-color: #007bff; - color: white; - box-shadow: 0 4px 12px rgba(0, 123, 255, 0.3); -} - /* Unified Modal */ .unified-modal { display: none; @@ -243,10 +629,10 @@ body, html { .modal-content { background-color: white; - border-radius: 8px; + border-radius: 12px; width: 400px; max-width: 90%; - box-shadow: 0 4px 20px rgba(0,0,0,0.2); + box-shadow: 0 8px 30px rgba(0,0,0,0.2); display: flex; flex-direction: column; } @@ -290,13 +676,15 @@ body, html { .modal-body input[type="text"], .modal-body input[type="number"], +.modal-body input[type="date"], .modal-body select, .modal-body textarea { width: 100%; padding: 8px; border: 1px solid #ccc; - border-radius: 4px; + border-radius: 6px; font-size: 14px; + font-family: inherit; } .modal-footer { @@ -308,20 +696,23 @@ body, html { } .btn-save { - background-color: #007bff; + background: linear-gradient(135deg, #6366f1, #4f46e5); color: white; border: none; - padding: 8px 16px; - border-radius: 4px; + padding: 8px 18px; + border-radius: 7px; cursor: pointer; + font-weight: 600; + font-size: 13px; } .btn-cancel { background-color: #f8f9fa; border: 1px solid #ddd; - padding: 8px 16px; - border-radius: 4px; + padding: 8px 18px; + border-radius: 7px; cursor: pointer; + font-size: 13px; } .form-group { @@ -340,7 +731,7 @@ body, html { border-radius: 4px; font-size: 13px; font-weight: 500; - pointer-events: none; /* Supaya tidak menghalangi klik ke map */ + pointer-events: none; z-index: 9999; white-space: nowrap; box-shadow: 0 2px 6px rgba(0,0,0,0.2); @@ -432,8 +823,8 @@ body, html { } /* Warna bubble per tipe */ -.emoji-marker .bubble.spbu-24 { background: linear-gradient(135deg, #22c55e, #16a34a); } -.emoji-marker .bubble.spbu-not24 { background: linear-gradient(135deg, #ef4444, #dc2626); } -.emoji-marker .bubble.ibadah { background: linear-gradient(135deg, #f97316, #ea580c); } -.emoji-marker .bubble.miskin-in { background: linear-gradient(135deg, #ef4444, #dc2626); } -.emoji-marker .bubble.miskin-out { background: linear-gradient(135deg, #22c55e, #16a34a); } +.emoji-marker .bubble.spbu-24 { background: linear-gradient(135deg, #22c55e, #16a34a); } +.emoji-marker .bubble.spbu-not24 { background: linear-gradient(135deg, #ef4444, #dc2626); } +.emoji-marker .bubble.ibadah { background: linear-gradient(135deg, #f97316, #ea580c); } +.emoji-marker .bubble.miskin-in { background: linear-gradient(135deg, #ef4444, #dc2626); } +.emoji-marker .bubble.miskin-out { background: linear-gradient(135deg, #22c55e, #16a34a); } diff --git a/assets/js/features/jalan.js b/assets/js/features/jalan.js index ccd8541..733b72e 100644 --- a/assets/js/features/jalan.js +++ b/assets/js/features/jalan.js @@ -16,6 +16,7 @@ function loadJalan() { addJalanToMap(item); }); } + if (window.refreshActivePanel) window.refreshActivePanel(); }); } diff --git a/assets/js/features/kemiskinan.js b/assets/js/features/kemiskinan.js index 91acce0..1f9fa55 100644 --- a/assets/js/features/kemiskinan.js +++ b/assets/js/features/kemiskinan.js @@ -1,10 +1,20 @@ // --- Fitur Pemetaan Kemiskinan --- +// Emoji per jenis ibadah +const IBADAH_EMOJI_MAP = { + 'Masjid': '🕌', + 'Gereja': '⛪', + 'Pura': '🛕', + 'Vihara': '🪷', + 'Kelenteng': '🏮', +}; + // Emoji Bubble Icon builder -function makeIbadahIcon() { +function makeIbadahIcon(jenis) { + const emot = IBADAH_EMOJI_MAP[jenis] || '🕌'; return L.divIcon({ className: '', - html: `
🕌
`, + html: `
${emot}
`, iconSize: [38, 38], iconAnchor: [19, 38], popupAnchor: [0, -40] @@ -22,10 +32,6 @@ function makeMiskinIcon(inRadius) { }); } -const ibadahIcon = makeIbadahIcon(); -const miskinMerahIcon = makeMiskinIcon(true); -const miskinHijauIcon = makeMiskinIcon(false); - let ibadahDataList = []; let miskinMarkerList = []; // Simpan referensi marker untuk update warna @@ -76,13 +82,14 @@ function loadRumahIbadah() { data.data.forEach(item => { addIbadahMarker(item); }); - updateSemuaWarnaMiskin(); // Update warna setelah memuat rumah ibadah + updateSemuaWarnaMiskin(); } + if (window.refreshActivePanel) window.refreshActivePanel(); }); } function addIbadahMarker(item) { - const marker = L.marker([item.lat, item.lng], { icon: ibadahIcon, draggable: true }); + const marker = L.marker([item.lat, item.lng], { icon: makeIbadahIcon(item.jenis), draggable: true }); // Lingkaran radius const circle = L.circle([item.lat, item.lng], { @@ -125,10 +132,12 @@ function addIbadahMarker(item) { marker.circleLayer = circle; const d = item; + const emot = IBADAH_EMOJI_MAP[d.jenis] || '🕌'; const popupContent = ` -
-

Rumah Ibadah ${d.nama}

-

Alamat: ${d.alamat}

+
+

${emot} ${d.nama}

+

Jenis: ${d.jenis || 'Masjid'}

+

Alamat: ${d.alamat}

Radius: ${d.radius} m

@@ -185,6 +194,16 @@ map.on('click', function(e) {
+
+ + +
@@ -196,7 +215,7 @@ map.on('click', function(e) { `; openModal("Tambah Rumah Ibadah", bodyHTML, function() { - window.saveNewIbadah(lat, lng, 'modalIbadahNama', 'modalIbadahAlamat', 'modalIbadahRadius'); + window.saveNewIbadah(lat, lng, 'modalIbadahNama', 'modalIbadahJenis', 'modalIbadahAlamat', 'modalIbadahRadius'); }); window.deactivateAddMode(); @@ -212,6 +231,16 @@ map.on('click', function(e) {
+
+ + +
@@ -223,7 +252,7 @@ map.on('click', function(e) { `; openModal("Tambah Rumah Ibadah", bodyHTML, function() { - window.saveNewIbadah(lat, lng, 'modalIbadahNama', 'modalIbadahAlamat', 'modalIbadahRadius'); + window.saveNewIbadah(lat, lng, 'modalIbadahNama', 'modalIbadahJenis', 'modalIbadahAlamat', 'modalIbadahRadius'); }); window.deactivateAddMode(); @@ -231,27 +260,23 @@ map.on('click', function(e) { } }); -window.saveNewIbadah = function(lat, lng, namaId, alamatId, radiusId) { - const nama = document.getElementById(namaId).value; +window.saveNewIbadah = function(lat, lng, namaId, jenisId, alamatId, radiusId) { + const nama = document.getElementById(namaId).value; + const jenis = document.getElementById(jenisId).value; const alamat = document.getElementById(alamatId).value; const radius = document.getElementById(radiusId).value; - if (!nama) { - alert("Nama Rumah Ibadah harus diisi!"); - return; - } + if (!nama) { alert("Nama Rumah Ibadah harus diisi!"); return; } fetch('api/rumah_ibadah/create.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ nama, alamat, radius, lat, lng }) + body: JSON.stringify({ nama, jenis, alamat, radius, lat, lng }) }) .then(res => res.json()) .then(data => { - if(data.status === 'success') { - closeModal(); - loadRumahIbadah(); - } else { alert(data.message); } + if(data.status === 'success') { closeModal(); loadRumahIbadah(); } + else { alert(data.message); } }); }; @@ -262,11 +287,19 @@ window.openEditIbadahModal = function(id) { }); if (!d) return; + const jenisOpts = ['Masjid','Gereja','Pura','Vihara','Kelenteng'].map(j => + `` + ).join(''); + const bodyHTML = `
+
+ + +
@@ -278,7 +311,7 @@ window.openEditIbadahModal = function(id) { `; map.closePopup(); openModal("Edit Rumah Ibadah", bodyHTML, function() { - window.saveEditIbadah(d.id, d.lat, d.lng, 'editIbadahNama', 'editIbadahAlamat', 'editIbadahRadius'); + window.saveEditIbadah(d.id, d.lat, d.lng, 'editIbadahNama', 'editIbadahJenis', 'editIbadahAlamat', 'editIbadahRadius'); }); }; @@ -293,18 +326,19 @@ window.previewRadius = function(id, newRadius) { }); }; -window.saveEditIbadah = function(id, lat, lng, namaId, alamatId, radiusId) { - const nama = document.getElementById(namaId).value; +window.saveEditIbadah = function(id, lat, lng, namaId, jenisId, alamatId, radiusId) { + const nama = document.getElementById(namaId).value; + const jenis = document.getElementById(jenisId).value; const alamat = document.getElementById(alamatId).value; const radius = document.getElementById(radiusId).value; - updateIbadah(id, nama, alamat, radius, lat, lng); + updateIbadah(id, nama, jenis, alamat, radius, lat, lng); }; -function updateIbadah(id, nama, alamat, radius, lat, lng) { +function updateIbadah(id, nama, jenis, alamat, radius, lat, lng) { fetch('api/rumah_ibadah/update.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ id, nama, alamat, radius, lat, lng }) + body: JSON.stringify({ id, nama, jenis, alamat, radius, lat, lng }) }).then(res => res.json()).then(data => { if(data.status === 'success') { map.closePopup(); loadRumahIbadah(); } }); @@ -336,19 +370,22 @@ function loadPendudukMiskin() { }); updateSemuaWarnaMiskin(); } + if (window.refreshActivePanel) window.refreshActivePanel(); }); } function addMiskinMarker(item) { - const marker = L.marker([item.lat, item.lng], { icon: miskinHijauIcon, draggable: true }); + const marker = L.marker([item.lat, item.lng], { icon: makeMiskinIcon(false), draggable: true }); marker.miskinData = item; const d = item; const popupContent = ` -
-

Penduduk Miskin ${d.nama}

-

Bantuan: ${d.kategori_bantuan}

-
+
+

🏠 ${d.nama}

+

Bantuan: ${d.kategori_bantuan}

+

Jiwa: ${d.jumlah_jiwa || '-'}

+
+
@@ -374,34 +411,48 @@ function addMiskinMarker(item) { } window.formAddMiskin = function(lat, lng) { - const popupContent = ` -
- +
+
+ + +
`; map.closePopup(); openModal("Edit Penduduk Miskin", bodyHTML, function() { - window.saveEditMiskin(d.id, d.lat, d.lng, 'editMiskinNama', 'editMiskinKategori'); + window.saveEditMiskin(d.id, d.lat, d.lng, 'editMiskinNama', 'editMiskinKategori', 'editMiskinJiwa'); }); }; -window.saveEditMiskin = function(id, lat, lng, namaId, kategoriId) { - const nama = document.getElementById(namaId).value; +window.saveEditMiskin = function(id, lat, lng, namaId, kategoriId, jiwaId) { + const nama = document.getElementById(namaId).value; const kategori_bantuan = document.getElementById(kategoriId).value; + const jumlah_jiwa = jiwaId ? document.getElementById(jiwaId).value : 1; fetch('api/penduduk_miskin/update.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ id, nama, kategori_bantuan, lat, lng }) + body: JSON.stringify({ id, nama, kategori_bantuan, jumlah_jiwa, lat, lng }) }).then(res => res.json()).then(data => { if(data.status === 'success') { closeModal(); loadPendudukMiskin(); } }); diff --git a/assets/js/features/parsil.js b/assets/js/features/parsil.js index bc78b1d..7895ad2 100644 --- a/assets/js/features/parsil.js +++ b/assets/js/features/parsil.js @@ -17,6 +17,7 @@ function loadParsil() { addParsilToMap(item); }); } + if (window.refreshActivePanel) window.refreshActivePanel(); }); } diff --git a/assets/js/features/spbu.js b/assets/js/features/spbu.js index 0974c9e..499209a 100644 --- a/assets/js/features/spbu.js +++ b/assets/js/features/spbu.js @@ -29,6 +29,7 @@ function loadSpbu() { addSpbuMarker(item); }); } + if (window.refreshActivePanel) window.refreshActivePanel(); }); } diff --git a/assets/js/map.js b/assets/js/map.js index 96e8a3e..bb3352f 100644 --- a/assets/js/map.js +++ b/assets/js/map.js @@ -107,22 +107,19 @@ window.showSearchResults = function(query) { }; // UI Logic: Custom Layer Control Toggle -const layerBtn = document.getElementById('layerBtn'); +const layerBtn = document.getElementById('layerBtn'); const layerPanel = document.getElementById('layerPanel'); layerBtn.addEventListener('click', function() { - if (layerPanel.style.display === 'block') { - layerPanel.style.display = 'none'; - } else { - layerPanel.style.display = 'block'; - } + layerPanel.style.display = layerPanel.style.display === 'block' ? 'none' : 'block'; }); -// Sembunyikan layer panel saat klik di luar area (pada map) +// Sembunyikan layer panel saat klik di peta map.on('click', function() { layerPanel.style.display = 'none'; }); + // Logic untuk Toggle Layer Visibility document.getElementById('layerSpbu').addEventListener('change', function(e) { e.target.checked ? map.addLayer(spbuLayer) : map.removeLayer(spbuLayer); @@ -248,18 +245,7 @@ window.closeConfirmModal = function() { confirmModal.classList.remove('show'); }; -// --- Action Menu Logic --- -const actionMenuBtn = document.getElementById('actionMenuBtn'); -const actionMenu = document.getElementById('actionMenu'); - -actionMenuBtn.addEventListener('click', function() { - if (actionMenu.style.display === 'flex') { - actionMenu.style.display = 'none'; - window.deactivateAddMode(); - } else { - actionMenu.style.display = 'flex'; - } -}); +// --- Action Menu Logic (replaced by left sidebar) --- window.currentAddMode = null; // 'spbu' atau 'rumah_ibadah' window.currentDrawMode = null; // 'polyline' atau 'polygon' @@ -279,19 +265,14 @@ window.activateAddMode = function(mode) { window.currentAddMode = mode; window.currentDrawMode = null; - - // Update button UI - document.querySelectorAll('.action-menu button').forEach(btn => btn.classList.remove('active')); - - if (mode === 'spbu') { - document.getElementById('btnMenuSpbu').classList.add('active'); - if (window.cursorTooltip) window.cursorTooltip.textContent = 'Klik untuk Tambah SPBU'; - } - if (mode === 'rumah_ibadah') { - document.getElementById('btnMenuIbadah').classList.add('active'); - if (window.cursorTooltip) window.cursorTooltip.textContent = 'Klik untuk Tambah Rumah Ibadah'; - } - + + // Tooltip + const tooltips = { + 'spbu': 'Klik untuk Tambah SPBU', + 'rumah_ibadah': 'Klik untuk Tambah Rumah Ibadah' + }; + if (window.cursorTooltip && tooltips[mode]) window.cursorTooltip.textContent = tooltips[mode]; + // Ubah kursor map menjadi crosshair document.getElementById('map').style.cursor = 'crosshair'; }; @@ -303,7 +284,6 @@ window.deactivateAddMode = function() { window.activeDrawHandler.disable(); window.activeDrawHandler = null; } - document.querySelectorAll('.action-menu button').forEach(btn => btn.classList.remove('active')); document.getElementById('map').style.cursor = ''; if (window.cursorTooltip) window.cursorTooltip.style.display = 'none'; }; diff --git a/assets/js/panel.js b/assets/js/panel.js new file mode 100644 index 0000000..8fca1a2 --- /dev/null +++ b/assets/js/panel.js @@ -0,0 +1,552 @@ +// ===== Panel Management ===== +// Mengelola Left Sidebar Toggle + Right Panel + Layer Control + +(function () { + // ---- Konstanta Jenis Ibadah ---- + const IBADAH_EMOJI = { + 'Masjid': '🕌', + 'Gereja': '⛪', + 'Pura': '🛕', + 'Vihara': '🪷', + 'Kelenteng': '🏮', + }; + window.IBADAH_EMOJI = IBADAH_EMOJI; + + // ---- State ---- + let activePanel = null; + + // ---- Elements ---- + const sidebarToggleBtn = document.getElementById('sidebarToggleBtn'); + const sidebarToggleIcon = document.getElementById('sidebarToggleIcon'); + const leftSidebar = document.getElementById('leftSidebar'); + const rightPanel = document.getElementById('rightPanel'); + const rightPanelTitle = document.getElementById('rightPanelTitle'); + const rightPanelActions = document.getElementById('rightPanelActions'); + const rightPanelBody = document.getElementById('rightPanelBody'); + const rightPanelClose = document.getElementById('rightPanelClose'); + + // ---- Sidebar Toggle ---- + sidebarToggleBtn.addEventListener('click', function () { + const isOpen = leftSidebar.style.display !== 'none'; + if (isOpen) { + leftSidebar.style.display = 'none'; + sidebarToggleBtn.classList.remove('open'); + sidebarToggleIcon.className = 'fas fa-chevron-right'; + } else { + leftSidebar.style.display = 'flex'; + sidebarToggleBtn.classList.add('open'); + sidebarToggleIcon.className = 'fas fa-chevron-left'; + } + }); + + // ---- Sidebar Buttons ---- + document.querySelectorAll('.sidebar-btn').forEach(btn => { + btn.addEventListener('click', function () { + const panel = this.dataset.panel; + if (activePanel === panel) { + closePanel(); + } else { + openPanel(panel); + } + }); + }); + + rightPanelClose.addEventListener('click', closePanel); + + // ---- Open / Close Panel ---- + function openPanel(panel) { + activePanel = panel; + rightPanel.classList.add('open'); + document.querySelectorAll('.sidebar-btn').forEach(b => b.classList.remove('active')); + const activeBtn = document.querySelector(`.sidebar-btn[data-panel="${panel}"]`); + if (activeBtn) activeBtn.classList.add('active'); + renderPanel(panel); + } + + function closePanel() { + activePanel = null; + rightPanel.classList.remove('open'); + document.querySelectorAll('.sidebar-btn').forEach(b => b.classList.remove('active')); + } + + window.refreshActivePanel = function () { + if (activePanel && activePanel !== 'layer') renderPanel(activePanel); + }; + + // ---- Render Panel by Type ---- + function renderPanel(type) { + rightPanelBody.innerHTML = '
Memuat data...
'; + rightPanelActions.innerHTML = ''; + + switch (type) { + case 'spbu': renderSpbuPanel(); break; + case 'jalan': renderJalanPanel(); break; + case 'parsil': renderParsilPanel(); break; + case 'ibadah': renderIbadahPanel(); break; + case 'miskin': renderMiskinPanel(); break; + } + } + + // ========================== + // ===== SPBU Panel ========= + // ========================== + function renderSpbuPanel() { + rightPanelTitle.textContent = '⛽ SPBU'; + rightPanelActions.innerHTML = ` + `; + document.getElementById('btnPanelAddSpbu').addEventListener('click', () => { + window.activateAddMode('spbu'); + }); + + const items = []; + spbuLayer.eachLayer(l => { if (l.spbuData) items.push(l.spbuData); }); + + if (!items.length) { + rightPanelBody.innerHTML = '
Belum ada data SPBU
'; + return; + } + + rightPanelBody.innerHTML = ''; + items.forEach(d => { + const bdg = d.is_24_jam + ? '24 Jam' + : 'Tidak 24 Jam'; + const card = document.createElement('div'); + card.className = 'data-card'; + card.innerHTML = ` +
+
+
+
${escHtml(d.nama)}
+
📞 ${d.no_wa || '-'}
+ ${bdg} +
+
+ + +
+
`; + card.querySelector('.btn-card-edit').addEventListener('click', (e) => { e.stopPropagation(); openEditSpbuModal(d.id); }); + card.querySelector('.btn-card-delete').addEventListener('click', (e) => { e.stopPropagation(); deleteSpbu(d.id); }); + card.addEventListener('click', () => flyToSpbu(d.id)); + rightPanelBody.appendChild(card); + }); + } + + function flyToSpbu(id) { + spbuLayer.eachLayer(l => { + if (l.spbuData && l.spbuData.id == id) { map.setView(l.getLatLng(), 17); l.openPopup(); } + }); + } + + // ========================== + // ===== Jalan Panel ======== + // ========================== + function renderJalanPanel() { + rightPanelTitle.textContent = '🛣️ Jalan'; + rightPanelActions.innerHTML = ` + `; + document.getElementById('btnPanelAddJalan').addEventListener('click', () => { + window.activateDraw('polyline'); + }); + + const items = []; + jalanLayer.eachLayer(l => { if (l.jalanData) items.push(l.jalanData); }); + + if (!items.length) { + rightPanelBody.innerHTML = '
Belum ada data jalan
'; + return; + } + + const statusBadge = { + 'Nasional' : 'Nasional', + 'Provinsi' : 'Provinsi', + 'Kabupaten': 'Kabupaten', + }; + + rightPanelBody.innerHTML = ''; + items.forEach(d => { + const km = (d.panjang / 1000).toFixed(2); + const card = document.createElement('div'); + card.className = 'data-card'; + card.innerHTML = ` +
+
🛣️
+
+
${escHtml(d.nama)}
+
📏 ${km} km
+ ${statusBadge[d.status] || ''} +
+
+ + +
+
`; + card.querySelector('.btn-card-edit').addEventListener('click', (e) => { e.stopPropagation(); openEditJalanModal(d.id); }); + card.querySelector('.btn-card-delete').addEventListener('click', (e) => { e.stopPropagation(); deleteJalan(d.id); }); + card.addEventListener('click', () => flyToJalan(d.id)); + rightPanelBody.appendChild(card); + }); + } + + function flyToJalan(id) { + jalanLayer.eachLayer(l => { + if (l.jalanData && l.jalanData.id == id && l.getBounds) { + map.fitBounds(l.getBounds(), { padding: [40, 40] }); l.openPopup(); + } + }); + } + + // ========================== + // ===== Parsil Panel ======= + // ========================== + function renderParsilPanel() { + rightPanelTitle.textContent = '🗺️ Parsil Tanah'; + rightPanelActions.innerHTML = ` + `; + document.getElementById('btnPanelAddParsil').addEventListener('click', () => { + window.activateDraw('polygon'); + }); + + const items = []; + parsilLayer.eachLayer(l => { if (l.parsilData) items.push(l.parsilData); }); + + if (!items.length) { + rightPanelBody.innerHTML = '
Belum ada data parsil
'; + return; + } + + const statusBadge = { + 'SHM': 'SHM', + 'HGB': 'HGB', + 'HGU': 'HGU', + 'HP' : 'HP', + }; + + rightPanelBody.innerHTML = ''; + items.forEach(d => { + const luas = d.luas >= 10000 + ? (d.luas / 10000).toFixed(2) + ' ha' + : d.luas.toFixed(0) + ' m²'; + const card = document.createElement('div'); + card.className = 'data-card'; + card.innerHTML = ` +
+
🗺️
+
+
${escHtml(d.nama || 'Tanpa Nama')}
+
📐 ${luas}
+ ${statusBadge[d.status] || ''} +
+
+ + +
+
`; + card.querySelector('.btn-card-edit').addEventListener('click', (e) => { e.stopPropagation(); openEditParsilModal(d.id); }); + card.querySelector('.btn-card-delete').addEventListener('click', (e) => { e.stopPropagation(); deleteParsil(d.id); }); + card.addEventListener('click', () => flyToParsil(d.id)); + rightPanelBody.appendChild(card); + }); + } + + function flyToParsil(id) { + parsilLayer.eachLayer(l => { + if (l.parsilData && l.parsilData.id == id && l.getBounds) { + map.fitBounds(l.getBounds(), { padding: [40, 40] }); l.openPopup(); + } + }); + } + + // ========================== + // ===== Ibadah Panel ======= + // ========================== + function renderIbadahPanel() { + rightPanelTitle.textContent = '🕌 Rumah Ibadah'; + rightPanelActions.innerHTML = ` + `; + document.getElementById('btnPanelAddIbadah').addEventListener('click', () => { + window.activateAddMode('rumah_ibadah'); + }); + + const items = []; + rumahIbadahLayer.eachLayer(l => { + if (l.ibadahData && l instanceof L.Marker) items.push(l.ibadahData); + }); + + if (!items.length) { + rightPanelBody.innerHTML = '
Belum ada data rumah ibadah
'; + return; + } + + rightPanelBody.innerHTML = ''; + items.forEach(d => { + const emoji = IBADAH_EMOJI[d.jenis] || '🕌'; + const card = document.createElement('div'); + card.className = 'data-card'; + card.innerHTML = ` +
+
${emoji}
+
+
${escHtml(d.nama)}
+
${escHtml(d.jenis || 'Masjid')} • 📡 ${d.radius} m
+
+
+ + +
+
`; + card.querySelector('.btn-card-edit').addEventListener('click', (e) => { e.stopPropagation(); openEditIbadahModal(d.id); }); + card.querySelector('.btn-card-delete').addEventListener('click', (e) => { e.stopPropagation(); deleteIbadah(d.id); }); + card.addEventListener('click', () => flyToIbadah(d.id)); + rightPanelBody.appendChild(card); + }); + } + + function flyToIbadah(id) { + rumahIbadahLayer.eachLayer(l => { + if (l.ibadahData && l.ibadahData.id == id && l instanceof L.Marker) { + map.setView(l.getLatLng(), 17); l.openPopup(); + } + }); + } + + // ========================== + // ===== Miskin Panel ======= + // ========================== + function renderMiskinPanel() { + rightPanelTitle.textContent = '🏠 Penduduk Miskin'; + rightPanelActions.innerHTML = ` + + `; + + // Tombol Tambah: buka form via right-click popup di peta + document.getElementById('btnPanelTambahMiskin').addEventListener('click', () => { + // Aktifkan mode: klik kiri di peta = tambah miskin + window.currentAddMode = 'miskin_click'; + document.getElementById('map').style.cursor = 'crosshair'; + if (window.cursorTooltip) { + window.cursorTooltip.textContent = 'Klik di peta untuk tentukan lokasi penduduk miskin'; + } + }); + + document.getElementById('btnPanelImportMiskin').addEventListener('click', () => { + alert('Fitur impor CSV akan segera tersedia.'); + }); + + const all = []; + pendudukMiskinLayer.eachLayer(l => { if (l.miskinData) all.push(l.miskinData); }); + + if (!all.length) { + rightPanelBody.innerHTML = '
Belum ada data penduduk miskin
'; + return; + } + + const inRadius = (d) => { + if (typeof ibadahDataList === 'undefined') return false; + for (const ib of ibadahDataList) { + const dist = L.latLng(d.lat, d.lng).distanceTo(L.latLng(ib.lat, ib.lng)); + if (dist <= ib.radius) return true; + } + return false; + }; + + rightPanelBody.innerHTML = ''; + + const terurusItems = all.filter(d => inRadius(d)); + const tidakItems = all.filter(d => !inRadius(d)); + + if (terurusItems.length) { + const h1 = document.createElement('div'); + h1.className = 'panel-section-title'; + h1.innerHTML = `✅ Terurus (${terurusItems.length})`; + rightPanelBody.appendChild(h1); + terurusItems.forEach(d => rightPanelBody.appendChild(buildMiskinCard(d, true))); + } + + if (tidakItems.length) { + const h2 = document.createElement('div'); + h2.className = 'panel-section-title'; + h2.innerHTML = `⚠️ Tidak Terurus (${tidakItems.length})`; + rightPanelBody.appendChild(h2); + tidakItems.forEach(d => rightPanelBody.appendChild(buildMiskinCard(d, false))); + } + } + + function buildMiskinCard(d, terurus) { + const iconCls = terurus ? 'card-icon-miskin-in' : 'card-icon-miskin-out'; + const badge = d.kategori_bantuan === 'Makan' + ? 'Bantuan Makan' + : 'Pemberdayaan'; + + const card = document.createElement('div'); + card.className = 'data-card'; + card.dataset.miskinId = d.id; + card.innerHTML = ` +
+
🏠
+
+
${escHtml(d.nama)}
+
👨‍👩‍👧 ${d.jumlah_jiwa || '-'} jiwa
+ ${badge} +
+
+ + +
+
+
+
Kategori Bantuan${escHtml(d.kategori_bantuan)}
+
Jumlah Jiwa${d.jumlah_jiwa || '-'}
+
Status${terurus ? 'Terurus ✅' : 'Tidak Terurus ⚠️'}
+ +
`; + + card.querySelector('.btn-card-edit').addEventListener('click', (e) => { e.stopPropagation(); openEditMiskinModal(d.id); }); + card.querySelector('.btn-card-delete').addEventListener('click', (e) => { e.stopPropagation(); deleteMiskin(d.id); }); + card.querySelector('.btn-log-bantuan').addEventListener('click', (e) => { e.stopPropagation(); openLogBantuan(d.id, d.nama); }); + + card.querySelector('.data-card-main').addEventListener('click', () => { + card.classList.toggle('expanded'); + flyToMiskin(d.id); + }); + + return card; + } + + function flyToMiskin(id) { + pendudukMiskinLayer.eachLayer(l => { + if (l.miskinData && l.miskinData.id == id) { + map.setView(l.getLatLng(), 17); l.openPopup(); + } + }); + } + + // ---- Hook: klik peta saat mode miskin_click ---- + // Ditangkap oleh kemiskinan.js via contextmenu — mode ini pakai klik kiri + map.on('click', function(e) { + if (window.currentAddMode === 'miskin_click') { + window.currentAddMode = null; + document.getElementById('map').style.cursor = ''; + if (window.cursorTooltip) window.cursorTooltip.style.display = 'none'; + // Buka form tambah miskin + if (typeof window.formAddMiskin === 'function') { + window.formAddMiskin(e.latlng.lat, e.latlng.lng); + } + } + }); + + // ========================== + // ===== Log Bantuan Modal == + // ========================== + const logModal = document.getElementById('logBantuanModal'); + const logTitle = document.getElementById('logBantuanTitle'); + const logList = document.getElementById('logBantuanList'); + const logSaveBtn = document.getElementById('logSaveBtn'); + const logIbadahSel = document.getElementById('logIbadahId'); + let _logMiskinId = null; + + window.openLogBantuan = function (miskinId, nama) { + _logMiskinId = miskinId; + logTitle.textContent = `Log Bantuan — ${nama}`; + logModal.classList.add('show'); + + // Isi dropdown ibadah + logIbadahSel.innerHTML = ''; + if (typeof ibadahDataList !== 'undefined') { + ibadahDataList.forEach(ib => { + const opt = document.createElement('option'); + opt.value = ib.id; + opt.textContent = `${IBADAH_EMOJI[ib.jenis] || '🕌'} ${ib.nama}`; + logIbadahSel.appendChild(opt); + }); + } + + // Set tanggal default hari ini + document.getElementById('logTanggal').valueAsDate = new Date(); + fetchLogBantuan(miskinId); + }; + + window.closeLogBantuanModal = function () { + logModal.classList.remove('show'); + _logMiskinId = null; + }; + + function fetchLogBantuan(miskinId) { + logList.innerHTML = '
Memuat...
'; + fetch(`api/log_bantuan/read.php?miskin_id=${miskinId}`) + .then(r => r.json()) + .then(data => { + if (!data.data || !data.data.length) { + logList.innerHTML = '
Belum ada riwayat bantuan
'; + return; + } + logList.innerHTML = ''; + data.data.forEach(log => { + const tgl = new Date(log.tanggal).toLocaleDateString('id-ID', { day:'2-digit', month:'short', year:'numeric' }); + const item = document.createElement('div'); + item.className = 'log-item'; + item.innerHTML = ` +
+
+
${escHtml(log.tipe_bantuan)}
+
${IBADAH_EMOJI[log.jenis_ibadah] || '🕌'} ${escHtml(log.nama_ibadah)} • ${tgl}
+ ${log.keterangan ? `
${escHtml(log.keterangan)}
` : ''} +
`; + logList.appendChild(item); + }); + }) + .catch(() => { + logList.innerHTML = '
Gagal memuat data
'; + }); + } + + logSaveBtn.addEventListener('click', function () { + const ibadah_id = logIbadahSel.value; + const tipe_bantuan = document.getElementById('logTipeBantuan').value; + const tanggal = document.getElementById('logTanggal').value; + const keterangan = document.getElementById('logKeterangan').value; + + if (!ibadah_id) { alert('Pilih rumah ibadah terlebih dahulu!'); return; } + if (!tanggal) { alert('Tanggal harus diisi!'); return; } + + fetch('api/log_bantuan/create.php', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ miskin_id: _logMiskinId, ibadah_id, tipe_bantuan, tanggal, keterangan }) + }) + .then(r => r.json()) + .then(data => { + if (data.status === 'success') { + document.getElementById('logKeterangan').value = ''; + fetchLogBantuan(_logMiskinId); + } else { + alert(data.message || 'Gagal menyimpan'); + } + }); + }); + + // ---- Utility ---- + function escHtml(str) { + if (!str) return ''; + return String(str).replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); + } + + // ---- Expose ---- + window.openRightPanel = openPanel; + +})(); diff --git a/index.php b/index.php index 597aff5..a3ff930 100644 --- a/index.php +++ b/index.php @@ -46,18 +46,49 @@
- - - - + + + + + +
+
+

Data

+ +
+
+
+
Pilih menu di kiri untuk menampilkan data
+
+
+ +
@@ -168,7 +199,8 @@
-
+ +
@@ -206,6 +238,56 @@ + +
+ +
+ @@ -225,7 +307,7 @@ - +