menambahkan fitur edit data pengguna dan memperbarui landing page
This commit is contained in:
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
$conn = new mysqli("localhost", "root", "", "webgis"); // UBAH DB
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
|
||||||
if ($data && isset($data['id'])) {
|
|
||||||
$id = $data['id'];
|
|
||||||
$stmt = $conn->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();
|
|
||||||
?>
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
|
|
||||||
// Konfigurasi Database (Sesuaikan dengan milik Anda)
|
|
||||||
$host = "localhost";
|
|
||||||
$user = "root";
|
|
||||||
$pass = "";
|
|
||||||
$db = "webgis"; // UBAH INI
|
|
||||||
|
|
||||||
$conn = new mysqli($host, $user, $pass, $db);
|
|
||||||
|
|
||||||
if ($conn->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();
|
|
||||||
?>
|
|
||||||
@@ -23,20 +23,6 @@
|
|||||||
<button class="mode-btn active" data-mode="point" onclick="ubahMode('point')">
|
<button class="mode-btn active" data-mode="point" onclick="ubahMode('point')">
|
||||||
<i class="fa-solid fa-gas-pump"></i> SPBU
|
<i class="fa-solid fa-gas-pump"></i> SPBU
|
||||||
</button>
|
</button>
|
||||||
<button class="mode-btn" data-mode="polyline" onclick="ubahMode('polyline')">
|
|
||||||
<i class="fa-solid fa-road"></i> Jalan
|
|
||||||
</button>
|
|
||||||
<button class="mode-btn" data-mode="polygon" onclick="ubahMode('polygon')">
|
|
||||||
<i class="fa-solid fa-draw-polygon"></i> Kavling
|
|
||||||
</button>
|
|
||||||
</div><br>
|
|
||||||
<div class="mode-buttons">
|
|
||||||
<button class="mode-btn" data-mode="edit_jalan" onclick="ubahMode('edit_jalan')" style="background-color: #fcf3cf; border-color: #f1c40f; color: #d35400;">
|
|
||||||
<i class="fa-solid fa-pen-ruler"></i> Edit Jalan
|
|
||||||
</button>
|
|
||||||
<button class="mode-btn" data-mode="edit_kavling" onclick="ubahMode('edit_kavling')" style="background-color: #d4efdf; border-color: #27ae60; color: #1e8449;">
|
|
||||||
<i class="fa-solid fa-pen-ruler"></i> Edit Kavling
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
<?php
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
|
||||||
|
|
||||||
$sql = "SELECT * FROM area_polygon";
|
|
||||||
$result = $conn->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();
|
|
||||||
?>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
$conn = new mysqli("localhost", "root", "", "webgis"); // UBAH DB
|
|
||||||
|
|
||||||
$sql = "SELECT * FROM jalan_polyline";
|
|
||||||
$result = $conn->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();
|
|
||||||
?>
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
<?php
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
|
||||||
|
|
||||||
// Pastikan data yang dikirim dari JS sesuai dengan variabel baru
|
|
||||||
if ($data && isset($data['nama_kavling']) && isset($data['geojson'])) {
|
|
||||||
$nama_kavling = $data['nama_kavling'];
|
|
||||||
$status = $data['status'];
|
|
||||||
$luas_m2 = $data['luas_m2'];
|
|
||||||
|
|
||||||
// Ubah object GeoJSON menjadi string agar bisa disimpan di MySQL
|
|
||||||
$geojson_string = json_encode($data['geojson']);
|
|
||||||
|
|
||||||
// Sesuaikan query INSERT dengan nama kolom di tabel database yang baru
|
|
||||||
$stmt = $conn->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();
|
|
||||||
?>
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
$conn = new mysqli("localhost", "root", "", "webgis"); // UBAH DB
|
|
||||||
|
|
||||||
$data = json_decode(file_get_contents("php://input"), true);
|
|
||||||
|
|
||||||
if ($data && isset($data['nama_jalan']) && isset($data['geojson'])) {
|
|
||||||
$nama_jalan = $data['nama_jalan'];
|
|
||||||
$status = $data['status'];
|
|
||||||
$panjang_m = $data['panjang_m'];
|
|
||||||
$geojson_string = json_encode($data['geojson']); // Jadikan string untuk disimpan
|
|
||||||
|
|
||||||
$stmt = $conn->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();
|
|
||||||
?>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
// Sesuaikan dengan konfigurasi database Anda
|
|
||||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
|
||||||
|
|
||||||
if ($conn->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();
|
|
||||||
?>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<?php
|
|
||||||
header('Content-Type: application/json');
|
|
||||||
// Sesuaikan dengan konfigurasi database Anda
|
|
||||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
|
||||||
|
|
||||||
if ($conn->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();
|
|
||||||
?>
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
require_once '../../auth.php';
|
||||||
|
requireRole('admin');
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$conn = new mysqli("localhost", "root", "", "webgis");
|
||||||
|
|
||||||
|
$id = (int) $_GET['id'];
|
||||||
|
$stmt = $conn->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();
|
||||||
|
?>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
require_once '../../auth.php';
|
||||||
|
requireRole('admin');
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$conn = new mysqli("localhost", "root", "", "webgis");
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
|
||||||
|
$id = (int) $data['id'];
|
||||||
|
|
||||||
|
// Tidak boleh hapus diri sendiri
|
||||||
|
if ($id === (int) $_SESSION['user']) {
|
||||||
|
echo json_encode(["status" => "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();
|
||||||
|
?>
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
require_once '../../auth.php';
|
||||||
|
requireRole('admin');
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$conn = new mysqli("localhost", "root", "", "webgis");
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
|
||||||
|
if (!$data || !isset($data['id'])) {
|
||||||
|
echo json_encode(["status" => "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();
|
||||||
|
?>
|
||||||
@@ -1,83 +1,72 @@
|
|||||||
|
/* ===== RESET & BASE ===== */
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
height: 100vh; width: 100vw; margin: 0; padding: 0;
|
height: 100vh;
|
||||||
display: flex; font-family: Arial, sans-serif; overflow: hidden;
|
width: 100vw;
|
||||||
}
|
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 {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
font-family: 'Segoe UI', Arial, sans-serif;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons input, .action-buttons select {
|
/* ===== SIDEBAR ===== */
|
||||||
width: 100%; margin-bottom: 15px; padding: 8px; box-sizing: border-box;
|
#sidebar {
|
||||||
border: 1px solid #ccc; border-radius: 4px;
|
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 {
|
/* Header sidebar */
|
||||||
width: 100%; padding: 10px; margin-bottom: 8px; cursor: pointer;
|
.sidebar-header {
|
||||||
border-radius: 5px; font-weight: bold;
|
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; }
|
.sidebar-body {
|
||||||
.btn-danger { background-color: #e74c3c; color: white; border: none; }
|
padding: 16px;
|
||||||
|
display: flex;
|
||||||
#map-container { flex: 1; position: relative; }
|
flex-direction: column;
|
||||||
#map { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }
|
gap: 10px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== USER INFO ===== */
|
||||||
.user-info {
|
.user-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 12px;
|
padding: 16px 12px;
|
||||||
background: #f0f4f8;
|
background: #f0f4f8;
|
||||||
border-radius: 8px;
|
border-radius: 10px;
|
||||||
margin-bottom: 12px;
|
gap: 6px;
|
||||||
gap: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-info i {
|
.user-info i {
|
||||||
font-size: 28px;
|
font-size: 32px;
|
||||||
color: #1B2A4A;
|
color: #1B2A4A;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-info span {
|
.user-info span {
|
||||||
font-weight: 600;
|
font-weight: 700;
|
||||||
font-size: 14px;
|
font-size: 15px;
|
||||||
color: #1B2A4A;
|
color: #1B2A4A;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,52 +74,219 @@ html, body {
|
|||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
background: #1B2A4A;
|
background: #1B2A4A;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 2px 8px;
|
padding: 3px 10px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
text-transform: uppercase;
|
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 {
|
.viewer-info {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #888;
|
color: #888;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 10px;
|
padding: 12px;
|
||||||
}
|
background: #f0f4f8;
|
||||||
|
border-radius: 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== TOMBOL LOGIN & LOGOUT ===== */
|
||||||
.btn-login {
|
.btn-login {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px;
|
||||||
background: #1B2A4A;
|
background: #1B2A4A;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
border-radius: 10px;
|
||||||
|
text-decoration: none;
|
||||||
.btn-logout {
|
font-size: 14px;
|
||||||
background: #fdecea;
|
font-weight: 600;
|
||||||
color: #c0392b;
|
transition: background 0.2s;
|
||||||
}
|
width: 100%;
|
||||||
|
border: none;
|
||||||
.menu-link,
|
cursor: pointer;
|
||||||
.btn-logout,
|
|
||||||
.btn-login {
|
|
||||||
width: auto; /* tidak full width lagi */
|
|
||||||
display: block;
|
|
||||||
margin: 0 auto 8px auto;
|
|
||||||
padding: 10px 24px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-login:hover { background: #253d6e; }
|
.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; }
|
.btn-logout:hover { background: #f5b7b1; }
|
||||||
.menu-link:hover { background: #dce4f0; }
|
|
||||||
|
/* ===== 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;
|
||||||
|
}
|
||||||
@@ -17,46 +17,62 @@ $role = $isLoggedIn ? $_SESSION['role'] : 'viewer';
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="sidebar">
|
<div id="sidebar">
|
||||||
<h3>Menu Pemetaan</h3>
|
|
||||||
|
|
||||||
<?php if ($isLoggedIn): ?>
|
<div class="sidebar-header">
|
||||||
<!-- Tampil kalau sudah login -->
|
<i class="fa-solid fa-map-location-dot"></i>
|
||||||
<div class="user-info">
|
Sistem Pemetaan
|
||||||
<i class="fa-solid fa-circle-user"></i>
|
</div>
|
||||||
<span><?= htmlspecialchars($_SESSION['nama']) ?></span>
|
|
||||||
<small><?= ucfirst($role) ?></small>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if (in_array($role, ['admin', 'operator'])): ?>
|
<div class="sidebar-body">
|
||||||
<div class="mode-buttons">
|
|
||||||
<button class="mode-btn" data-mode="prasejahtera" onclick="ubahMode('prasejahtera')">
|
<?php if ($isLoggedIn): ?>
|
||||||
<i class="fa-solid fa-house-chimney-crack"></i> Prasejahtera
|
|
||||||
</button>
|
<div class="user-info">
|
||||||
<button class="mode-btn mode-ibadah" data-mode="ibadah" onclick="ubahMode('ibadah')">
|
<i class="fa-solid fa-circle-user"></i>
|
||||||
<i class="fa-solid fa-place-of-worship"></i> Rumah Ibadah
|
<span><?= htmlspecialchars($_SESSION['nama']) ?></span>
|
||||||
</button>
|
<small><?= ucfirst($role) ?></small>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if ($role === 'admin'): ?>
|
<?php if (in_array($role, ['admin', 'operator'])): ?>
|
||||||
<a href="users.php" class="menu-link">
|
<div class="sidebar-divider"></div>
|
||||||
<i class="fa-solid fa-users-gear"></i> Kelola User
|
<span class="sidebar-label">Input Data</span>
|
||||||
|
<div class="mode-buttons">
|
||||||
|
<button class="mode-btn" data-mode="prasejahtera" onclick="ubahMode('prasejahtera')">
|
||||||
|
<i class="fa-solid fa-house-chimney-crack"></i>
|
||||||
|
Prasejahtera
|
||||||
|
</button>
|
||||||
|
<button class="mode-btn mode-ibadah" data-mode="ibadah" onclick="ubahMode('ibadah')">
|
||||||
|
<i class="fa-solid fa-place-of-worship"></i>
|
||||||
|
Rumah Ibadah
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($role === 'admin'): ?>
|
||||||
|
<div class="sidebar-divider"></div>
|
||||||
|
<span class="sidebar-label">Manajemen</span>
|
||||||
|
<a href="users.php" class="menu-link">
|
||||||
|
<i class="fa-solid fa-users-gear"></i> Kelola User
|
||||||
|
</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="sidebar-divider"></div>
|
||||||
|
<a href="logout.php" class="btn-logout">
|
||||||
|
<i class="fa-solid fa-right-from-bracket"></i> Logout
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<div class="viewer-info">
|
||||||
|
<i class="fa-solid fa-eye"></i> Anda melihat sebagai <b>Viewer</b>
|
||||||
|
</div>
|
||||||
|
<a href="login.php" class="btn-login">
|
||||||
|
<i class="fa-solid fa-right-to-bracket"></i> Login
|
||||||
|
</a>
|
||||||
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<a href="logout.php" class="btn-logout">
|
</div>
|
||||||
<i class="fa-solid fa-right-from-bracket"></i> Logout
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
<!-- Tampil kalau belum login (viewer) -->
|
|
||||||
<p class="viewer-info">
|
|
||||||
<i class="fa-solid fa-eye"></i> Anda melihat sebagai <b>Viewer</b>
|
|
||||||
</p>
|
|
||||||
<a href="login.php" class="btn-login">
|
|
||||||
<i class="fa-solid fa-right-to-bracket"></i> Login
|
|
||||||
</a>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="map-container">
|
<div id="map-container">
|
||||||
|
|||||||
+196
-55
@@ -17,7 +17,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
|||||||
if (!$nama || !$username || !$password || !in_array($role, ['admin', 'operator'])) {
|
if (!$nama || !$username || !$password || !in_array($role, ['admin', 'operator'])) {
|
||||||
$error = "Semua field wajib diisi dengan benar.";
|
$error = "Semua field wajib diisi dengan benar.";
|
||||||
} else {
|
} else {
|
||||||
// Cek apakah username sudah ada
|
|
||||||
$cek = $conn->prepare("SELECT id FROM users WHERE username = ?");
|
$cek = $conn->prepare("SELECT id FROM users WHERE username = ?");
|
||||||
$cek->bind_param("s", $username);
|
$cek->bind_param("s", $username);
|
||||||
$cek->execute();
|
$cek->execute();
|
||||||
@@ -43,8 +42,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
|||||||
// --- HAPUS USER ---
|
// --- HAPUS USER ---
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'hapus') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'hapus') {
|
||||||
$id = (int) $_POST['id'];
|
$id = (int) $_POST['id'];
|
||||||
|
|
||||||
// Tidak boleh hapus diri sendiri
|
|
||||||
if ($id === (int) $_SESSION['user']) {
|
if ($id === (int) $_SESSION['user']) {
|
||||||
$error = "Tidak bisa menghapus akun yang sedang aktif.";
|
$error = "Tidak bisa menghapus akun yang sedang aktif.";
|
||||||
} else {
|
} else {
|
||||||
@@ -59,7 +56,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- AMBIL SEMUA USER ---
|
|
||||||
$users = $conn->query("SELECT id, nama, username, role, created_at FROM users ORDER BY created_at DESC");
|
$users = $conn->query("SELECT id, nama, username, role, created_at FROM users ORDER BY created_at DESC");
|
||||||
$conn->close();
|
$conn->close();
|
||||||
?>
|
?>
|
||||||
@@ -79,7 +75,6 @@ $conn->close();
|
|||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NAVBAR */
|
|
||||||
.navbar {
|
.navbar {
|
||||||
background: #1B2A4A;
|
background: #1B2A4A;
|
||||||
color: white;
|
color: white;
|
||||||
@@ -89,10 +84,7 @@ $conn->close();
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar h1 {
|
.navbar h1 { font-size: 18px; font-weight: 600; }
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navbar a {
|
.navbar a {
|
||||||
color: white;
|
color: white;
|
||||||
@@ -107,18 +99,21 @@ $conn->close();
|
|||||||
|
|
||||||
.navbar a:hover { opacity: 1; }
|
.navbar a:hover { opacity: 1; }
|
||||||
|
|
||||||
/* CONTAINER */
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 900px;
|
max-width: 1100px;
|
||||||
margin: 32px auto;
|
margin: 32px auto;
|
||||||
padding: 0 20px;
|
padding: 0 20px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 320px;
|
grid-template-columns: 1fr 300px;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CARD */
|
thead th:last-child,
|
||||||
|
tbody td:last-child {
|
||||||
|
min-width: 160px;
|
||||||
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
@@ -137,9 +132,11 @@ $conn->close();
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Header edit punya warna berbeda */
|
||||||
|
.card-header.edit { background: #2980b9; }
|
||||||
|
|
||||||
.card-body { padding: 20px; }
|
.card-body { padding: 20px; }
|
||||||
|
|
||||||
/* ALERT */
|
|
||||||
.alert {
|
.alert {
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -153,12 +150,7 @@ $conn->close();
|
|||||||
.alert-success { background: #eafaf1; color: #1e8449; }
|
.alert-success { background: #eafaf1; color: #1e8449; }
|
||||||
.alert-error { background: #fdecea; color: #c0392b; }
|
.alert-error { background: #fdecea; color: #c0392b; }
|
||||||
|
|
||||||
/* TABEL */
|
table { width: 100%; border-collapse: collapse; font-size: 14px; }
|
||||||
table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
thead th {
|
thead th {
|
||||||
background: #f0f4f8;
|
background: #f0f4f8;
|
||||||
@@ -177,11 +169,7 @@ $conn->close();
|
|||||||
}
|
}
|
||||||
|
|
||||||
tbody tr:hover { background: #fafbfc; }
|
tbody tr:hover { background: #fafbfc; }
|
||||||
|
tbody td { padding: 12px 14px; color: #333; }
|
||||||
tbody td {
|
|
||||||
padding: 12px 14px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -204,10 +192,11 @@ $conn->close();
|
|||||||
margin-left: 4px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-hapus {
|
.action-buttons { display: flex; gap: 6px; }
|
||||||
|
|
||||||
|
.btn-edit, .btn-hapus {
|
||||||
background: none;
|
background: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: #e74c3c;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
@@ -215,10 +204,15 @@ $conn->close();
|
|||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-edit { color: #2980b9; }
|
||||||
|
.btn-hapus { color: #e74c3c; }
|
||||||
|
|
||||||
|
.btn-edit:hover { background: #e8f4fd; }
|
||||||
.btn-hapus:hover { background: #fdecea; }
|
.btn-hapus:hover { background: #fdecea; }
|
||||||
|
|
||||||
|
.btn-edit:disabled,
|
||||||
.btn-hapus:disabled { opacity: 0.3; cursor: not-allowed; }
|
.btn-hapus:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||||
|
|
||||||
/* FORM */
|
|
||||||
.form-group { margin-bottom: 14px; }
|
.form-group { margin-bottom: 14px; }
|
||||||
|
|
||||||
.form-group label {
|
.form-group label {
|
||||||
@@ -243,14 +237,17 @@ $conn->close();
|
|||||||
}
|
}
|
||||||
|
|
||||||
.form-group input:focus,
|
.form-group input:focus,
|
||||||
.form-group select:focus {
|
.form-group select:focus { border-color: #1B2A4A; }
|
||||||
border-color: #1B2A4A;
|
|
||||||
|
.form-group .hint {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #aaa;
|
||||||
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-submit {
|
.btn-submit {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 11px;
|
padding: 11px;
|
||||||
background: #1B2A4A;
|
|
||||||
color: white;
|
color: white;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
@@ -262,13 +259,44 @@ $conn->close();
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-submit:hover { background: #253d6e; }
|
.btn-submit.tambah { background: #1B2A4A; }
|
||||||
|
.btn-submit.tambah:hover { background: #253d6e; }
|
||||||
|
.btn-submit.simpan { background: #2980b9; }
|
||||||
|
.btn-submit.simpan:hover { background: #2471a3; }
|
||||||
|
|
||||||
|
.btn-batal {
|
||||||
|
width: 100%;
|
||||||
|
padding: 9px;
|
||||||
|
background: none;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #888;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-batal:hover { background: #f0f4f8; }
|
||||||
|
|
||||||
@media (max-width: 680px) {
|
@media (max-width: 680px) {
|
||||||
.container { grid-template-columns: 1fr; }
|
.container { grid-template-columns: 1fr; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pastikan kolom Aksi cukup lebar */
|
||||||
|
tbody td:last-child {
|
||||||
|
white-space: nowrap;
|
||||||
|
min-width: 130px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -291,15 +319,13 @@ $conn->close();
|
|||||||
|
|
||||||
<?php if ($error): ?>
|
<?php if ($error): ?>
|
||||||
<div class="alert alert-error">
|
<div class="alert alert-error">
|
||||||
<i class="fa-solid fa-circle-exclamation"></i>
|
<i class="fa-solid fa-circle-exclamation"></i> <?= $error ?>
|
||||||
<?= $error ?>
|
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($success): ?>
|
<?php if ($success): ?>
|
||||||
<div class="alert alert-success">
|
<div class="alert alert-success">
|
||||||
<i class="fa-solid fa-circle-check"></i>
|
<i class="fa-solid fa-circle-check"></i> <?= $success ?>
|
||||||
<?= $success ?>
|
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
@@ -332,14 +358,17 @@ $conn->close();
|
|||||||
</td>
|
</td>
|
||||||
<td><?= date('d M Y', strtotime($u['created_at'])) ?></td>
|
<td><?= date('d M Y', strtotime($u['created_at'])) ?></td>
|
||||||
<td>
|
<td>
|
||||||
<form method="POST" onsubmit="return konfirmasiHapus(this)">
|
<div class="action-buttons">
|
||||||
<input type="hidden" name="action" value="hapus">
|
<button class="btn-edit"
|
||||||
<input type="hidden" name="id" value="<?= $u['id'] ?>">
|
onclick="bukaFormEdit(<?= $u['id'] ?>, '<?= htmlspecialchars($u['nama'], ENT_QUOTES) ?>', '<?= htmlspecialchars($u['username'], ENT_QUOTES) ?>', '<?= $u['role'] ?>')">
|
||||||
<button type="submit" class="btn-hapus"
|
<i class="fa-solid fa-pen-to-square"></i> Edit
|
||||||
|
</button>
|
||||||
|
<button class="btn-hapus"
|
||||||
|
onclick="hapusUser(<?= $u['id'] ?>)"
|
||||||
<?= $u['id'] == $_SESSION['user'] ? 'disabled title="Tidak bisa hapus akun sendiri"' : '' ?>>
|
<?= $u['id'] == $_SESSION['user'] ? 'disabled title="Tidak bisa hapus akun sendiri"' : '' ?>>
|
||||||
<i class="fa-solid fa-trash"></i> Hapus
|
<i class="fa-solid fa-trash"></i> Hapus
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endwhile; ?>
|
<?php endwhile; ?>
|
||||||
@@ -348,40 +377,59 @@ $conn->close();
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- FORM TAMBAH USER -->
|
<!-- PANEL KANAN: FORM TAMBAH / EDIT -->
|
||||||
<div class="card">
|
<div class="card" id="form-card">
|
||||||
<div class="card-header">
|
|
||||||
<i class="fa-solid fa-user-plus"></i> Tambah User Baru
|
<!-- Header: berubah sesuai mode -->
|
||||||
|
<div class="card-header" id="form-header">
|
||||||
|
<i class="fa-solid fa-user-plus"></i>
|
||||||
|
<span id="form-title">Tambah User Baru</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form method="POST">
|
<form method="POST" id="form-tambah" onsubmit="return validasiForm()">
|
||||||
<input type="hidden" name="action" value="tambah">
|
<input type="hidden" name="action" value="tambah" id="form-action">
|
||||||
|
<input type="hidden" id="edit-id" value="">
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Nama Lengkap</label>
|
<label>Nama Lengkap</label>
|
||||||
<input type="text" name="nama" placeholder="Contoh: Budi Santoso" required>
|
<input type="text" name="nama" id="input-nama"
|
||||||
|
placeholder="Contoh: Budi Santoso" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Username</label>
|
<label>Username</label>
|
||||||
<input type="text" name="username" placeholder="Contoh: budi123" required>
|
<input type="text" name="username" id="input-username"
|
||||||
|
placeholder="Contoh: budi123" required>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Password</label>
|
<label>Password</label>
|
||||||
<input type="password" name="password" placeholder="Min. 6 karakter" required>
|
<input type="password" name="password" id="input-password"
|
||||||
|
placeholder="Min. 6 karakter">
|
||||||
|
<p class="hint" id="password-hint" style="display:none;">
|
||||||
|
<i class="fa-solid fa-circle-info"></i>
|
||||||
|
Kosongkan jika tidak ingin mengubah password
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Role</label>
|
<label>Role</label>
|
||||||
<select name="role">
|
<select name="role" id="input-role">
|
||||||
<option value="operator">Operator</option>
|
<option value="operator">Operator</option>
|
||||||
<option value="admin">Admin</option>
|
<option value="admin">Admin</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn-submit">
|
<button type="submit" class="btn-submit tambah" id="btn-submit">
|
||||||
<i class="fa-solid fa-user-plus"></i> Tambah User
|
<i class="fa-solid fa-user-plus"></i>
|
||||||
|
<span id="btn-submit-text">Tambah User</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Tombol Batal hanya muncul saat mode Edit -->
|
||||||
|
<button type="button" class="btn-batal" id="btn-batal"
|
||||||
|
style="display:none;" onclick="batalEdit()">
|
||||||
|
<i class="fa-solid fa-xmark"></i> Batal Edit
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -390,8 +438,101 @@ $conn->close();
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function konfirmasiHapus(form) {
|
const SESSION_USER_ID = <?= (int) $_SESSION['user'] ?>;
|
||||||
return confirm("Yakin ingin menghapus user ini?");
|
let modeEdit = false;
|
||||||
|
|
||||||
|
function bukaFormEdit(id, nama, username, role) {
|
||||||
|
modeEdit = true;
|
||||||
|
|
||||||
|
// Isi form dengan data user yang dipilih
|
||||||
|
document.getElementById('edit-id').value = id;
|
||||||
|
document.getElementById('input-nama').value = nama;
|
||||||
|
document.getElementById('input-username').value = username;
|
||||||
|
document.getElementById('input-role').value = role;
|
||||||
|
document.getElementById('input-password').value = '';
|
||||||
|
|
||||||
|
// Ubah tampilan form ke mode Edit
|
||||||
|
document.getElementById('form-header').classList.add('edit');
|
||||||
|
document.getElementById('form-title').textContent = 'Edit User';
|
||||||
|
document.getElementById('form-header').querySelector('i').className = 'fa-solid fa-user-pen';
|
||||||
|
document.getElementById('btn-submit').className = 'btn-submit simpan';
|
||||||
|
document.getElementById('btn-submit-text').textContent = 'Simpan Perubahan';
|
||||||
|
document.getElementById('btn-submit').querySelector('i').className = 'fa-solid fa-save';
|
||||||
|
document.getElementById('password-hint').style.display = 'block';
|
||||||
|
document.getElementById('btn-batal').style.display = 'block';
|
||||||
|
document.getElementById('input-password').required = false;
|
||||||
|
|
||||||
|
// Scroll ke form (berguna di mobile)
|
||||||
|
document.getElementById('form-card').scrollIntoView({ behavior: 'smooth' });
|
||||||
|
}
|
||||||
|
|
||||||
|
function batalEdit() {
|
||||||
|
modeEdit = false;
|
||||||
|
|
||||||
|
// Reset form ke mode Tambah
|
||||||
|
document.getElementById('form-tambah').reset();
|
||||||
|
document.getElementById('edit-id').value = '';
|
||||||
|
|
||||||
|
document.getElementById('form-header').classList.remove('edit');
|
||||||
|
document.getElementById('form-title').textContent = 'Tambah User Baru';
|
||||||
|
document.getElementById('form-header').querySelector('i').className = 'fa-solid fa-user-plus';
|
||||||
|
document.getElementById('btn-submit').className = 'btn-submit tambah';
|
||||||
|
document.getElementById('btn-submit-text').textContent = 'Tambah User';
|
||||||
|
document.getElementById('btn-submit').querySelector('i').className = 'fa-solid fa-user-plus';
|
||||||
|
document.getElementById('password-hint').style.display = 'none';
|
||||||
|
document.getElementById('btn-batal').style.display = 'none';
|
||||||
|
document.getElementById('input-password').required = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function validasiForm() {
|
||||||
|
if (!modeEdit) return true; // Mode tambah, biarkan PHP handle
|
||||||
|
|
||||||
|
// Mode edit: kirim via fetch, bukan submit form biasa
|
||||||
|
let id = document.getElementById('edit-id').value;
|
||||||
|
let nama = document.getElementById('input-nama').value.trim();
|
||||||
|
let username = document.getElementById('input-username').value.trim();
|
||||||
|
let password = document.getElementById('input-password').value;
|
||||||
|
let role = document.getElementById('input-role').value;
|
||||||
|
|
||||||
|
if (!nama || !username) {
|
||||||
|
alert('Nama dan username wajib diisi.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('api/users/update_user.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ id, nama, username, password, role })
|
||||||
|
})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
// Reload halaman untuk refresh tabel
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
alert('Gagal: ' + (data.message || 'Terjadi kesalahan'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return false; // Cegah submit form biasa
|
||||||
|
}
|
||||||
|
|
||||||
|
function hapusUser(id) {
|
||||||
|
if (!confirm('Yakin ingin menghapus user ini?')) return;
|
||||||
|
|
||||||
|
fetch('api/users/hapus_user.php', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ id: id })
|
||||||
|
})
|
||||||
|
.then(res => res.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
window.location.reload();
|
||||||
|
} else {
|
||||||
|
alert('Gagal: ' + (data.message || 'Terjadi kesalahan'));
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,70 +1,298 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="id">
|
<html lang="id">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Landing Page - Tugas WebGIS</title>
|
<title>WebGIS Portfolio — Muhammad Fauzi</title>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
<style>
|
<style>
|
||||||
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: Arial, sans-serif;
|
font-family: 'Segoe UI', Arial, sans-serif;
|
||||||
margin: 40px;
|
background: #f0f4f8;
|
||||||
background-color: #f4f4f9;
|
min-height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
/* ===== HEADER ===== */
|
||||||
max-width: 600px;
|
header {
|
||||||
margin: 0 auto;
|
background: #1B2A4A;
|
||||||
background: white;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
text-align: center;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-list {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-list li {
|
|
||||||
margin: 15px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link-list a {
|
|
||||||
display: block;
|
|
||||||
padding: 10px 15px;
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
color: white;
|
||||||
text-decoration: none;
|
padding: 48px 24px 40px;
|
||||||
border-radius: 5px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: bold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-list a:hover {
|
header .eyebrow {
|
||||||
background-color: #0056b3;
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 2px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: #7fa8d4;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header h1 {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header p {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #a8bdd4;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
header p span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== MAIN ===== */
|
||||||
|
main {
|
||||||
|
max-width: 960px;
|
||||||
|
margin: 40px auto;
|
||||||
|
padding: 0 24px 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-label {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #aab4c0;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== PROJECT GRID ===== */
|
||||||
|
.projects {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 14px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0,0,0,0.07);
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
transition: transform 0.2s, box-shadow 0.2s;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 8px 24px rgba(0,0,0,0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-banner {
|
||||||
|
height: 6px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-banner.green { background: #2ecc71; }
|
||||||
|
.card-banner.blue { background: #3498db; }
|
||||||
|
.card-banner.navy { background: #1B2A4A; }
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-eyebrow {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 700;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
color: #aab4c0;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-featured {
|
||||||
|
background: #1B2A4A;
|
||||||
|
color: white;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 20px;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1B2A4A;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-desc {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #666;
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.techstack {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 4px 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #f0f4f8;
|
||||||
|
color: #4a5568;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag.php { background: #e8f0fe; color: #3557a7; }
|
||||||
|
.tag.js { background: #fef9e7; color: #9a7d0a; }
|
||||||
|
.tag.mysql { background: #e8f8f5; color: #1a7a5e; }
|
||||||
|
.tag.leaflet { background: #fdf2f8; color: #7d3c98; }
|
||||||
|
.tag.css { background: #fef0e7; color: #a04000; }
|
||||||
|
|
||||||
|
.card-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: background 0.2s;
|
||||||
|
align-self: flex-start;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-btn.navy { background: #1B2A4A; }
|
||||||
|
.card-btn.navy:hover { background: #253d6e; }
|
||||||
|
.card-btn.green { background: #27ae60; }
|
||||||
|
.card-btn.green:hover { background: #1e8449; }
|
||||||
|
.card-btn.blue { background: #2980b9; }
|
||||||
|
.card-btn.blue:hover { background: #2471a3; }
|
||||||
|
|
||||||
|
/* ===== FOOTER ===== */
|
||||||
|
footer {
|
||||||
|
text-align: center;
|
||||||
|
padding: 24px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #aab4c0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="container">
|
<header>
|
||||||
<h2>Landing Page - Tugas WebGIS</h2>
|
<p class="eyebrow">Sistem Informasi Geografis</p>
|
||||||
<p style="text-align: center;">Nama: Muhammad Fauzi | NIM: D1041231083</p>
|
<h1>Tugas Besar</h1>
|
||||||
|
<p>
|
||||||
|
<span><i class="fa-solid fa-user"></i> Muhammad Fauzi</span>
|
||||||
|
<span><i class="fa-solid fa-id-card"></i> D1041231083</span>
|
||||||
|
<span><i class="fa-solid fa-university"></i> Informatika — UNTAN</span>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main>
|
||||||
|
|
||||||
|
<p class="section-label"><i class="fa-solid fa-folder-open"></i> Daftar Project</p>
|
||||||
|
|
||||||
|
<div class="projects">
|
||||||
|
|
||||||
|
<!-- ===== PERTEMUAN 01: Pemetaan SPBU ===== -->
|
||||||
|
<a href="./Pertemuan01/" class="card">
|
||||||
|
<div class="card-banner green"></div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-eyebrow">
|
||||||
|
<i class="fa-solid fa-calendar-days"></i> Pertemuan 1
|
||||||
|
</div>
|
||||||
|
<div class="card-title">Pemetaan Titik SPBU</div>
|
||||||
|
<p class="card-desc">
|
||||||
|
WebGIS dasar untuk menandai dan mengelola lokasi SPBU di peta menggunakan marker titik.
|
||||||
|
Mendukung operasi tambah, edit, dan hapus data langsung melalui popup di peta.
|
||||||
|
</p>
|
||||||
|
<div class="techstack">
|
||||||
|
<span class="tag leaflet"><i class="fa-solid fa-map"></i> Leaflet.js</span>
|
||||||
|
<span class="tag php">PHP</span>
|
||||||
|
<span class="tag mysql">MySQL</span>
|
||||||
|
<span class="tag js">JavaScript</span>
|
||||||
|
</div>
|
||||||
|
<span class="card-btn green">
|
||||||
|
<i class="fa-solid fa-arrow-right"></i> Buka Project
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- ===== PERTEMUAN 02: Pemetaan Jalan & Area ===== -->
|
||||||
|
<a href="./Pertemuan02/" class="card">
|
||||||
|
<div class="card-banner blue"></div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-eyebrow">
|
||||||
|
<i class="fa-solid fa-calendar-days"></i> Pertemuan 2
|
||||||
|
</div>
|
||||||
|
<div class="card-title">Pemetaan Jalan & Area</div>
|
||||||
|
<p class="card-desc">
|
||||||
|
WebGIS untuk menggambar dan menyimpan data jalan (polyline) serta area kavling (polygon)
|
||||||
|
secara interaktif di atas peta. Data tersimpan ke database dan dapat diedit ulang posisinya.
|
||||||
|
</p>
|
||||||
|
<div class="techstack">
|
||||||
|
<span class="tag leaflet"><i class="fa-solid fa-map"></i> Leaflet.js</span>
|
||||||
|
<span class="tag php">PHP</span>
|
||||||
|
<span class="tag mysql">MySQL</span>
|
||||||
|
<span class="tag js">JavaScript</span>
|
||||||
|
</div>
|
||||||
|
<span class="card-btn blue">
|
||||||
|
<i class="fa-solid fa-arrow-right"></i> Buka Project
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- ===== FINAL PROJECT: WebGIS Poverty Mapping ===== -->
|
||||||
|
<a href="./WebGISPovertyMapping/" class="card">
|
||||||
|
<div class="card-banner navy"></div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="card-eyebrow">
|
||||||
|
<i class="fa-solid fa-star"></i> Final Project
|
||||||
|
</div>
|
||||||
|
<div class="card-title">Pemetaan Kemiskinan</div>
|
||||||
|
<p class="card-desc">
|
||||||
|
WebGIS pemetaan rumah prasejahtera dan rumah ibadah dengan analisis spasial otomatis,
|
||||||
|
sistem login multi-role, dan manajemen data lengkap.
|
||||||
|
</p>
|
||||||
|
<div class="techstack">
|
||||||
|
<span class="tag leaflet"><i class="fa-solid fa-map"></i> Leaflet.js</span>
|
||||||
|
<span class="tag php">PHP</span>
|
||||||
|
<span class="tag mysql">MySQL</span>
|
||||||
|
<span class="tag js">JavaScript</span>
|
||||||
|
<span class="tag css">CSS</span>
|
||||||
|
</div>
|
||||||
|
<span class="card-btn navy">
|
||||||
|
<i class="fa-solid fa-arrow-right"></i> Buka Project
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
<ul class="link-list">
|
|
||||||
<li><a href="./Pertemuan01/">Tugas Pertemuan 1</a></li>
|
|
||||||
<li><a href="./Pertemuan02/">Tugas Pertemuan 2</a></li>
|
|
||||||
<li><a href="./WebGISPovertyMapping/">Tugas Poverty Mapping</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
© 2026 Muhammad Fauzi
|
||||||
|
</footer>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user