diff --git a/Pertemuan01/hapus_area.php b/Pertemuan01/hapus_area.php
deleted file mode 100644
index 819df19..0000000
--- a/Pertemuan01/hapus_area.php
+++ /dev/null
@@ -1,18 +0,0 @@
-prepare("DELETE FROM area_polygon WHERE id = ?");
- $stmt->bind_param("i", $id);
- if ($stmt->execute()) {
- echo json_encode(["status" => "success"]);
- } else {
- echo json_encode(["status" => "error", "message" => $stmt->error]);
- }
- $stmt->close();
-}
-$conn->close();
-?>
\ No newline at end of file
diff --git a/Pertemuan01/hapus_jalan.php b/Pertemuan01/hapus_jalan.php
deleted file mode 100644
index 175d531..0000000
--- a/Pertemuan01/hapus_jalan.php
+++ /dev/null
@@ -1,38 +0,0 @@
-connect_error) {
- echo json_encode(["status" => "error", "message" => "Koneksi database gagal"]);
- exit;
-}
-
-$data = json_decode(file_get_contents("php://input"), true);
-
-if ($data && isset($data['id'])) {
- $id = $data['id'];
-
- // Hapus data dari tabel jalan_polyline berdasarkan ID
- $stmt = $conn->prepare("DELETE FROM jalan_polyline WHERE id = ?");
- $stmt->bind_param("i", $id);
-
- if ($stmt->execute()) {
- echo json_encode(["status" => "success", "message" => "Garis jalan berhasil dihapus"]);
- } else {
- echo json_encode(["status" => "error", "message" => "Gagal menghapus data: " . $stmt->error]);
- }
-
- $stmt->close();
-} else {
- echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
-}
-
-$conn->close();
-?>
\ No newline at end of file
diff --git a/Pertemuan01/index.html b/Pertemuan01/index.html
index fa564f9..7bc731a 100644
--- a/Pertemuan01/index.html
+++ b/Pertemuan01/index.html
@@ -23,20 +23,6 @@
-
-
-
-
-
-
diff --git a/Pertemuan01/load_area.php b/Pertemuan01/load_area.php
deleted file mode 100644
index f583e4b..0000000
--- a/Pertemuan01/load_area.php
+++ /dev/null
@@ -1,20 +0,0 @@
-query($sql);
-$data_area = array();
-
-if ($result->num_rows > 0) {
- while($row = $result->fetch_assoc()) {
- // Mengubah string geojson dari database kembali menjadi Object JSON
- // Ini wajib agar Leaflet.geoJSON() di Javascript bisa merendernya
- $row['geojson'] = json_decode($row['geojson']);
- $data_area[] = $row;
- }
-}
-
-echo json_encode($data_area);
-$conn->close();
-?>
\ No newline at end of file
diff --git a/Pertemuan01/load_jalan.php b/Pertemuan01/load_jalan.php
deleted file mode 100644
index 7455a87..0000000
--- a/Pertemuan01/load_jalan.php
+++ /dev/null
@@ -1,18 +0,0 @@
-query($sql);
-$data_jalan = array();
-
-if ($result->num_rows > 0) {
- while($row = $result->fetch_assoc()) {
- // Parse string geojson menjadi object agar mudah dibaca Javascript
- $row['geojson'] = json_decode($row['geojson']);
- $data_jalan[] = $row;
- }
-}
-echo json_encode($data_jalan);
-$conn->close();
-?>
\ No newline at end of file
diff --git a/Pertemuan01/simpan_area.php b/Pertemuan01/simpan_area.php
deleted file mode 100644
index 566b5b0..0000000
--- a/Pertemuan01/simpan_area.php
+++ /dev/null
@@ -1,33 +0,0 @@
-prepare("INSERT INTO area_polygon (nama_kavling, status_kepemilikan, luas_m2, geojson) VALUES (?, ?, ?, ?)");
-
- // Parameter: "ssds" berarti String, String, Double (Desimal), String
- $stmt->bind_param("ssds", $nama_kavling, $status, $luas_m2, $geojson_string);
-
- if ($stmt->execute()) {
- echo json_encode(["status" => "success", "id" => $stmt->insert_id]);
- } else {
- echo json_encode(["status" => "error", "message" => $stmt->error]);
- }
- $stmt->close();
-} else {
- // Tambahkan pesan error jika data tidak lengkap
- echo json_encode(["status" => "error", "message" => "Data area tidak lengkap"]);
-}
-$conn->close();
-?>
\ No newline at end of file
diff --git a/Pertemuan01/simpan_jalan.php b/Pertemuan01/simpan_jalan.php
deleted file mode 100644
index 785c6b2..0000000
--- a/Pertemuan01/simpan_jalan.php
+++ /dev/null
@@ -1,26 +0,0 @@
-prepare("INSERT INTO jalan_polyline (nama_jalan, status, panjang_m, geojson) VALUES (?, ?, ?, ?)");
- $stmt->bind_param("ssds", $nama_jalan, $status, $panjang_m, $geojson_string);
-
- if ($stmt->execute()) {
- echo json_encode(["status" => "success", "id" => $stmt->insert_id]);
- } else {
- echo json_encode(["status" => "error", "message" => $stmt->error]);
- }
- $stmt->close();
-} else {
- echo json_encode(["status" => "error", "message" => "Data tidak lengkap"]);
-}
-$conn->close();
-?>
\ No newline at end of file
diff --git a/Pertemuan01/update_area.php b/Pertemuan01/update_area.php
deleted file mode 100644
index cf93d84..0000000
--- a/Pertemuan01/update_area.php
+++ /dev/null
@@ -1,31 +0,0 @@
-connect_error) {
- echo json_encode(["status" => "error", "message" => "Koneksi database gagal"]);
- exit;
-}
-
-$data = json_decode(file_get_contents("php://input"), true);
-
-if ($data && isset($data['id']) && isset($data['geojson'])) {
- $id = $data['id'];
- $luas_m2 = $data['luas_m2'];
- $geojson_string = json_encode($data['geojson']);
-
- $stmt = $conn->prepare("UPDATE area_polygon SET luas_m2 = ?, geojson = ? WHERE id = ?");
- $stmt->bind_param("dsi", $luas_m2, $geojson_string, $id);
-
- if ($stmt->execute()) {
- echo json_encode(["status" => "success"]);
- } else {
- echo json_encode(["status" => "error", "message" => $stmt->error]);
- }
- $stmt->close();
-} else {
- echo json_encode(["status" => "error", "message" => "Data tidak lengkap"]);
-}
-$conn->close();
-?>
\ No newline at end of file
diff --git a/Pertemuan01/update_jalan.php b/Pertemuan01/update_jalan.php
deleted file mode 100644
index e36d3ff..0000000
--- a/Pertemuan01/update_jalan.php
+++ /dev/null
@@ -1,31 +0,0 @@
-connect_error) {
- echo json_encode(["status" => "error", "message" => "Koneksi database gagal"]);
- exit;
-}
-
-$data = json_decode(file_get_contents("php://input"), true);
-
-if ($data && isset($data['id']) && isset($data['geojson'])) {
- $id = $data['id'];
- $panjang_m = $data['panjang_m'];
- $geojson_string = json_encode($data['geojson']);
-
- $stmt = $conn->prepare("UPDATE jalan_polyline SET panjang_m = ?, geojson = ? WHERE id = ?");
- $stmt->bind_param("dsi", $panjang_m, $geojson_string, $id);
-
- if ($stmt->execute()) {
- echo json_encode(["status" => "success"]);
- } else {
- echo json_encode(["status" => "error", "message" => $stmt->error]);
- }
- $stmt->close();
-} else {
- echo json_encode(["status" => "error", "message" => "Data tidak lengkap"]);
-}
-$conn->close();
-?>
\ No newline at end of file
diff --git a/WebGISPovertyMapping/api/users/get_user.php b/WebGISPovertyMapping/api/users/get_user.php
new file mode 100644
index 0000000..1a82274
--- /dev/null
+++ b/WebGISPovertyMapping/api/users/get_user.php
@@ -0,0 +1,19 @@
+prepare("SELECT id, nama, username, role FROM users WHERE id = ?");
+$stmt->bind_param("i", $id);
+$stmt->execute();
+$result = $stmt->get_result();
+$data = $result->fetch_assoc();
+
+echo $data ? json_encode($data) : json_encode(["status" => "error", "message" => "User tidak ditemukan"]);
+
+$stmt->close();
+$conn->close();
+?>
\ No newline at end of file
diff --git a/WebGISPovertyMapping/api/users/hapus_user.php b/WebGISPovertyMapping/api/users/hapus_user.php
new file mode 100644
index 0000000..0181104
--- /dev/null
+++ b/WebGISPovertyMapping/api/users/hapus_user.php
@@ -0,0 +1,28 @@
+ "error", "message" => "Tidak bisa menghapus akun sendiri"]);
+ exit;
+}
+
+$stmt = $conn->prepare("DELETE FROM users WHERE id = ?");
+$stmt->bind_param("i", $id);
+
+if ($stmt->execute()) {
+ echo json_encode(["status" => "success"]);
+} else {
+ echo json_encode(["status" => "error", "message" => $stmt->error]);
+}
+
+$stmt->close();
+$conn->close();
+?>
\ No newline at end of file
diff --git a/WebGISPovertyMapping/api/users/update_user.php b/WebGISPovertyMapping/api/users/update_user.php
new file mode 100644
index 0000000..1c2b289
--- /dev/null
+++ b/WebGISPovertyMapping/api/users/update_user.php
@@ -0,0 +1,55 @@
+ "error", "message" => "Data tidak lengkap"]);
+ exit;
+}
+
+$id = (int) $data['id'];
+$nama = trim($data['nama']);
+$username = trim($data['username']);
+$role = $data['role'];
+
+if (!$nama || !$username || !in_array($role, ['admin', 'operator'])) {
+ echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
+ exit;
+}
+
+// Cek username sudah dipakai user lain
+$cek = $conn->prepare("SELECT id FROM users WHERE username = ? AND id != ?");
+$cek->bind_param("si", $username, $id);
+$cek->execute();
+$cek->store_result();
+if ($cek->num_rows > 0) {
+ echo json_encode(["status" => "error", "message" => "Username sudah digunakan user lain"]);
+ $cek->close();
+ $conn->close();
+ exit;
+}
+$cek->close();
+
+// Update dengan atau tanpa password baru
+if (!empty($data['password'])) {
+ $hash = password_hash($data['password'], PASSWORD_DEFAULT);
+ $stmt = $conn->prepare("UPDATE users SET nama=?, username=?, password=?, role=? WHERE id=?");
+ $stmt->bind_param("ssssi", $nama, $username, $hash, $role, $id);
+} else {
+ $stmt = $conn->prepare("UPDATE users SET nama=?, username=?, role=? WHERE id=?");
+ $stmt->bind_param("sssi", $nama, $username, $role, $id);
+}
+
+if ($stmt->execute()) {
+ echo json_encode(["status" => "success"]);
+} else {
+ echo json_encode(["status" => "error", "message" => $stmt->error]);
+}
+
+$stmt->close();
+$conn->close();
+?>
\ No newline at end of file
diff --git a/WebGISPovertyMapping/assets/css/style.css b/WebGISPovertyMapping/assets/css/style.css
index b17bdfd..c89b3d7 100644
--- a/WebGISPovertyMapping/assets/css/style.css
+++ b/WebGISPovertyMapping/assets/css/style.css
@@ -1,83 +1,72 @@
+/* ===== RESET & BASE ===== */
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
html, body {
- height: 100vh; width: 100vw; margin: 0; padding: 0;
- display: flex; font-family: Arial, sans-serif; overflow: hidden;
-}
-
-#sidebar {
- width: 280px; background-color: #f8f9fa; padding: 20px;
- box-shadow: 2px 0 5px rgba(0,0,0,0.2); z-index: 1000; overflow-y: auto;
-}
-
-#sidebar h3 { margin-top: 0; border-bottom: 2px solid #ddd; padding-bottom: 10px; }
-
-/* Styling Ikon Mode */
-.mode-selector { margin-bottom: 20px; }
-.mode-buttons {
+ height: 100vh;
+ width: 100vw;
+ overflow: hidden;
display: flex;
- justify-content: center;
- gap: 8px;
- margin-bottom: 8px;
-}
-.mode-btn {
- flex: 0 0 auto; /* tidak melebar penuh */
- width: 110px;
- padding: 10px 8px;
- text-align: center;
-}
-.mode-btn i { font-size: 24px; margin-bottom: 8px; display: block; }
-.mode-btn:hover { background: #e9ecef; }
-
-/* Warna saat tombol mode aktif */
-.mode-btn.active[data-mode="point"] { border-color: #e74c3c; color: #e74c3c; background: #fadbd8; }
-.mode-btn.active[data-mode="polyline"] { border-color: #3498db; color: #3498db; background: #d6eaf8; }
-.mode-btn.active[data-mode="polygon"] { border-color: #2ecc71; color: #2ecc71; background: #d5f5e3; }
-.mode-btn.active[data-mode="prasejahtera"] { border-color: #c0392b; color: #ffffff; background: #e74c3c; }
-.mode-btn.active[data-mode="ibadah"] { border-color: #6c3483; color: #ffffff; background: #8e44ad; }
-/* Styling tombol edit aktif */
-.mode-btn.active[data-mode="edit_jalan"] { background-color: #f1c40f !important; color: white !important; }
-.mode-btn.active[data-mode="edit_kavling"] { background-color: #27ae60 !important; color: white !important; }
-
-/* Styling Input & Action Buttons */
-.action-buttons {
- display: none; background: #fff; padding: 15px;
- border-radius: 8px; border: 1px solid #ddd; margin-top: 10px; margin-bottom: 20px;
+ font-family: 'Segoe UI', Arial, sans-serif;
}
-.action-buttons input, .action-buttons select {
- width: 100%; margin-bottom: 15px; padding: 8px; box-sizing: border-box;
- border: 1px solid #ccc; border-radius: 4px;
+/* ===== SIDEBAR ===== */
+#sidebar {
+ width: 280px;
+ min-width: 280px;
+ background: white;
+ display: flex;
+ flex-direction: column;
+ padding: 0;
+ box-shadow: 2px 0 12px rgba(0,0,0,0.10);
+ z-index: 1000;
+ overflow-y: auto;
}
-.action-buttons button {
- width: 100%; padding: 10px; margin-bottom: 8px; cursor: pointer;
- border-radius: 5px; font-weight: bold;
+/* Header sidebar */
+.sidebar-header {
+ background: #1B2A4A;
+ color: white;
+ padding: 18px 20px;
+ font-size: 16px;
+ font-weight: 700;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ letter-spacing: 0.3px;
+ flex-shrink: 0;
}
-.btn-success { background-color: #2ecc71; color: white; border: none; }
-.btn-danger { background-color: #e74c3c; color: white; border: none; }
-
-#map-container { flex: 1; position: relative; }
-#map { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }
+.sidebar-body {
+ padding: 16px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ flex: 1;
+}
+/* ===== USER INFO ===== */
.user-info {
display: flex;
flex-direction: column;
align-items: center;
- padding: 12px;
+ padding: 16px 12px;
background: #f0f4f8;
- border-radius: 8px;
- margin-bottom: 12px;
- gap: 4px;
+ border-radius: 10px;
+ gap: 6px;
}
.user-info i {
- font-size: 28px;
+ font-size: 32px;
color: #1B2A4A;
}
.user-info span {
- font-weight: 600;
- font-size: 14px;
+ font-weight: 700;
+ font-size: 15px;
color: #1B2A4A;
}
@@ -85,52 +74,219 @@ html, body {
font-size: 11px;
background: #1B2A4A;
color: white;
- padding: 2px 8px;
+ padding: 3px 10px;
border-radius: 20px;
text-transform: uppercase;
+ letter-spacing: 0.5px;
}
+/* ===== DIVIDER ===== */
+.sidebar-divider {
+ height: 1px;
+ background: #e8edf2;
+ margin: 2px 0;
+}
+
+/* ===== LABEL SECTION ===== */
+.sidebar-label {
+ font-size: 11px;
+ font-weight: 700;
+ color: #aab4c0;
+ text-transform: uppercase;
+ letter-spacing: 0.8px;
+ padding: 0 2px;
+}
+
+/* ===== TOMBOL MODE (Prasejahtera & Rumah Ibadah) ===== */
+.mode-buttons {
+ display: flex;
+ gap: 8px;
+ justify-content: center;
+}
+
+.mode-btn {
+ flex: 1;
+ padding: 12px 6px;
+ background: #f0f4f8;
+ border: 2px solid transparent;
+ border-radius: 10px;
+ cursor: pointer;
+ font-size: 12px;
+ font-weight: 600;
+ color: #4a5568;
+ text-align: center;
+ transition: all 0.2s;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 6px;
+ line-height: 1.3;
+}
+
+.mode-btn i {
+ font-size: 20px;
+ color: #1B2A4A;
+ display: block;
+ margin-bottom: 0;
+}
+
+.mode-btn:hover {
+ background: #e2e8f0;
+ border-color: #1B2A4A;
+}
+
+/* Warna saat tombol mode aktif */
+.mode-btn.active,
+.mode-btn.active[data-mode="prasejahtera"] {
+ background: #e74c3c;
+ border-color: #c0392b;
+ color: white;
+}
+
+.mode-btn.active i,
+.mode-btn.active[data-mode="prasejahtera"] i {
+ color: white;
+}
+
+.mode-btn.active[data-mode="ibadah"],
+.mode-btn.mode-ibadah.active {
+ background: #8e44ad;
+ border-color: #6c3483;
+ color: white;
+}
+
+.mode-btn.active[data-mode="ibadah"] i,
+.mode-btn.mode-ibadah.active i {
+ color: white;
+}
+
+/* Mode lain (polyline, polygon, dll — tetap dipertahankan) */
+.mode-btn.active[data-mode="point"] { border-color: #e74c3c; color: #e74c3c; background: #fadbd8; }
+.mode-btn.active[data-mode="polyline"] { border-color: #3498db; color: #3498db; background: #d6eaf8; }
+.mode-btn.active[data-mode="polygon"] { border-color: #2ecc71; color: #2ecc71; background: #d5f5e3; }
+.mode-btn.active[data-mode="edit_jalan"] { background: #f1c40f; border-color: #d4ac0d; color: white; }
+.mode-btn.active[data-mode="edit_kavling"] { background: #27ae60; border-color: #1e8449; color: white; }
+
+/* ===== ACTION BUTTONS (panel dalam sidebar, dipertahankan) ===== */
+.action-buttons {
+ display: none;
+ background: #fff;
+ padding: 15px;
+ border-radius: 8px;
+ border: 1px solid #ddd;
+ margin-top: 4px;
+}
+
+.action-buttons input,
+.action-buttons select {
+ width: 100%;
+ margin-bottom: 15px;
+ padding: 8px;
+ box-sizing: border-box;
+ border: 1px solid #ccc;
+ border-radius: 4px;
+}
+
+.action-buttons button {
+ width: 100%;
+ padding: 10px;
+ margin-bottom: 8px;
+ cursor: pointer;
+ border-radius: 5px;
+ font-weight: bold;
+}
+
+.btn-success { background-color: #2ecc71; color: white; border: none; }
+.btn-danger { background-color: #e74c3c; color: white; border: none; }
+
+/* ===== MENU LINK (Kelola User) ===== */
+.menu-link {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 11px 14px;
+ background: #f0f4f8;
+ border-radius: 10px;
+ text-decoration: none;
+ font-size: 14px;
+ font-weight: 600;
+ color: #1B2A4A;
+ transition: background 0.2s;
+ width: 100%;
+ border: none;
+ cursor: pointer;
+}
+
+.menu-link:hover { background: #e2e8f0; }
+
+/* ===== VIEWER INFO ===== */
.viewer-info {
font-size: 13px;
color: #888;
text-align: center;
- margin-bottom: 10px;
-}
-
-.btn-login, .btn-logout, .menu-link {
- display: block;
- width: 100%;
- padding: 10px;
- text-align: center;
- border-radius: 8px;
- font-size: 14px;
- font-weight: 600;
- text-decoration: none;
- margin-bottom: 8px;
- cursor: pointer;
- border: none;
+ padding: 12px;
+ background: #f0f4f8;
+ border-radius: 10px;
}
+/* ===== TOMBOL LOGIN & LOGOUT ===== */
.btn-login {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ padding: 12px;
background: #1B2A4A;
color: white;
-}
-
-.btn-logout {
- background: #fdecea;
- color: #c0392b;
-}
-
-.menu-link,
-.btn-logout,
-.btn-login {
- width: auto; /* tidak full width lagi */
- display: block;
- margin: 0 auto 8px auto;
- padding: 10px 24px;
- text-align: center;
+ border-radius: 10px;
+ text-decoration: none;
+ font-size: 14px;
+ font-weight: 600;
+ transition: background 0.2s;
+ width: 100%;
+ border: none;
+ cursor: pointer;
}
.btn-login:hover { background: #253d6e; }
+
+.btn-logout {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ padding: 11px;
+ background: #fdecea;
+ color: #c0392b;
+ border-radius: 10px;
+ text-decoration: none;
+ font-size: 14px;
+ font-weight: 600;
+ border: none;
+ cursor: pointer;
+ transition: background 0.2s;
+ width: 100%;
+ margin-top: auto;
+}
+
.btn-logout:hover { background: #f5b7b1; }
-.menu-link:hover { background: #dce4f0; }
\ No newline at end of file
+
+/* ===== MAP CONTAINER ===== */
+#map-container {
+ flex: 1;
+ position: relative;
+}
+
+#map {
+ position: absolute;
+ top: 0; bottom: 0; left: 0; right: 0;
+}
+
+/* ===== LAYER CONTROL ===== */
+.leaflet-control-layers {
+ border-radius: 10px !important;
+ border: none !important;
+ box-shadow: 0 2px 12px rgba(0,0,0,0.12) !important;
+ font-family: 'Segoe UI', Arial, sans-serif !important;
+ font-size: 13px !important;
+}
\ No newline at end of file
diff --git a/WebGISPovertyMapping/index.php b/WebGISPovertyMapping/index.php
index c19a7e0..d269777 100644
--- a/WebGISPovertyMapping/index.php
+++ b/WebGISPovertyMapping/index.php
@@ -17,46 +17,62 @@ $role = $isLoggedIn ? $_SESSION['role'] : 'viewer';
-
-
-