menambahkan fitur login dan edit data
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
require_once '../../auth.php';
|
||||
requireRole('admin', 'operator');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
||||
|
||||
$id = (int) $_GET['id'];
|
||||
$stmt = $conn->prepare("SELECT * FROM rumah_prasejahtera 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" => "Data tidak ditemukan"]);
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
require_once '../../auth.php';
|
||||
requireRole('admin');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
// Pastikan nama database sudah benar
|
||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
require_once '../../auth.php';
|
||||
requireRole('admin', 'operator');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
||||
|
||||
|
||||
@@ -1,10 +1,42 @@
|
||||
<?php
|
||||
require_once '../../auth.php';
|
||||
requireRole('admin', 'operator');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
$conn = new mysqli('localhost', 'root', '', 'webgis');
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$stmt = $conn->prepare("UPDATE rumah_prasejahtera SET lat=?, lng=? WHERE id=?");
|
||||
$stmt->bind_param("ddi", $data['lat'], $data['lng'], $data['id']);
|
||||
echo $stmt->execute()
|
||||
? json_encode(['status' => 'success'])
|
||||
: json_encode(['status' => 'error']);
|
||||
$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;
|
||||
}
|
||||
|
||||
// Update koordinat saja (dari drag marker)
|
||||
if (isset($data['lat']) && isset($data['lng']) && count($data) === 3) {
|
||||
$stmt = $conn->prepare("UPDATE rumah_prasejahtera SET lat=?, lng=? WHERE id=?");
|
||||
$stmt->bind_param("ddi", $data['lat'], $data['lng'], $data['id']);
|
||||
|
||||
// Update semua field (dari form edit)
|
||||
} else {
|
||||
$stmt = $conn->prepare("UPDATE rumah_prasejahtera SET
|
||||
nama_kepala_keluarga=?, penghasilan=?, jumlah_anak=?, umur_anak=?,
|
||||
status_ortu=?, ada_pensiun=?, nominal_pensiun=?,
|
||||
ada_terusan=?, nominal_terusan=?, keterangan=?
|
||||
WHERE id=?");
|
||||
$stmt->bind_param("sdisssdsdsi",
|
||||
$data['nama_kk'], $data['penghasilan'], $data['jumlah_anak'],
|
||||
$data['umur_anak'], $data['status_ortu'], $data['ada_pensiun'],
|
||||
$data['nominal_pensiun'], $data['ada_terusan'], $data['nominal_terusan'],
|
||||
$data['keterangan'], $data['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,19 @@
|
||||
<?php
|
||||
require_once '../../auth.php';
|
||||
requireRole('admin', 'operator');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
||||
|
||||
$id = (int) $_GET['id'];
|
||||
$stmt = $conn->prepare("SELECT * FROM rumah_ibadah 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" => "Data tidak ditemukan"]);
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
?>
|
||||
@@ -1,4 +1,7 @@
|
||||
<?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);
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
require_once '../../auth.php';
|
||||
requireRole('admin', 'operator');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
$conn = new mysqli('localhost', 'root', '', 'webgis');
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
@@ -1,10 +1,33 @@
|
||||
<?php
|
||||
require_once '../../auth.php';
|
||||
requireRole('admin', 'operator');
|
||||
|
||||
header('Content-Type: application/json');
|
||||
$conn = new mysqli('localhost', 'root', '', 'webgis');
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
$stmt = $conn->prepare("UPDATE rumah_ibadah SET lat=?, lng=? WHERE id=?");
|
||||
$stmt->bind_param("ddi", $data['lat'], $data['lng'], $data['id']);
|
||||
echo $stmt->execute()
|
||||
? json_encode(['status' => 'success'])
|
||||
: json_encode(['status' => 'error']);
|
||||
$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;
|
||||
}
|
||||
|
||||
// Update koordinat saja (dari drag marker)
|
||||
if (isset($data['lat']) && isset($data['lng']) && count($data) === 3) {
|
||||
$stmt = $conn->prepare("UPDATE rumah_ibadah SET lat=?, lng=? WHERE id=?");
|
||||
$stmt->bind_param("ddi", $data['lat'], $data['lng'], $data['id']);
|
||||
|
||||
// Update semua field (dari form edit)
|
||||
} else {
|
||||
$stmt = $conn->prepare("UPDATE rumah_ibadah SET nama_ibadah=?, jenis=?, radius_m=? WHERE id=?");
|
||||
$stmt->bind_param("ssii", $data['nama_ibadah'], $data['jenis'], $data['radius_m'], $data['id']);
|
||||
}
|
||||
|
||||
if ($stmt->execute()) {
|
||||
echo json_encode(["status" => "success"]);
|
||||
} else {
|
||||
echo json_encode(["status" => "error", "message" => $stmt->error]);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
$conn->close();
|
||||
?>
|
||||
@@ -12,11 +12,17 @@ html, body {
|
||||
|
||||
/* Styling Ikon Mode */
|
||||
.mode-selector { margin-bottom: 20px; }
|
||||
.mode-buttons { display: flex; gap: 10px; justify-content: space-between; }
|
||||
.mode-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.mode-btn {
|
||||
flex: 1; padding: 15px 5px; background: #fff; border: 2px solid #ccc;
|
||||
border-radius: 8px; cursor: pointer; text-align: center;
|
||||
transition: all 0.3s ease; color: #555; font-size: 12px; font-weight: bold;
|
||||
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; }
|
||||
@@ -52,3 +58,79 @@ html, body {
|
||||
|
||||
#map-container { flex: 1; position: relative; }
|
||||
#map { position: absolute; top: 0; bottom: 0; left: 0; right: 0; }
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
background: #f0f4f8;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.user-info i {
|
||||
font-size: 28px;
|
||||
color: #1B2A4A;
|
||||
}
|
||||
|
||||
.user-info span {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: #1B2A4A;
|
||||
}
|
||||
|
||||
.user-info small {
|
||||
font-size: 11px;
|
||||
background: #1B2A4A;
|
||||
color: white;
|
||||
padding: 2px 8px;
|
||||
border-radius: 20px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.btn-login {
|
||||
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;
|
||||
}
|
||||
|
||||
.btn-login:hover { background: #253d6e; }
|
||||
.btn-logout:hover { background: #f5b7b1; }
|
||||
.menu-link:hover { background: #dce4f0; }
|
||||
@@ -117,6 +117,8 @@ function perbaruiWarnaPrasejahtera() {
|
||||
|
||||
// --- MANAJEMEN MODE UI ---
|
||||
function ubahMode(mode) {
|
||||
if (ROLE === 'viewer') return;
|
||||
|
||||
console.log('Mode diklik:', mode, '| Mode saat ini:', currentMode); // ← tambah ini
|
||||
|
||||
if (currentMode === mode) {
|
||||
@@ -169,7 +171,10 @@ function ubahMode(mode) {
|
||||
function loadIbadah() {
|
||||
fetch('api/rumahibadah/load_ibadah.php').then(res => res.json()).then(data => {
|
||||
data.forEach(ib => {
|
||||
let marker = L.marker([ib.lat, ib.lng], { icon: buatIkonIbadah(ib.jenis), draggable: true })
|
||||
let marker = L.marker([ib.lat, ib.lng], {
|
||||
icon: buatIkonIbadah(ib.jenis),
|
||||
draggable: ROLE === 'admin' || ROLE === 'operator'
|
||||
})
|
||||
.addTo(layerIbadah);
|
||||
|
||||
// Lingkaran radius
|
||||
@@ -178,9 +183,27 @@ function loadIbadah() {
|
||||
fillColor: '#8e44ad', fillOpacity: 0.1, weight: 1, dashArray: '5,5'
|
||||
}).addTo(layerIbadah);
|
||||
|
||||
marker.bindPopup(`<b>${ib.nama_ibadah}</b><br>Jenis Rumah Ibadah: ${ib.jenis}<br>Jangkauan Bantuan: ${ib.radius_m} m<hr>
|
||||
<button onclick="hapusIbadah(${ib.id})" style="color:red; width:100%; cursor:pointer;">
|
||||
<i class="fa-solid fa-trash"></i> Hapus</button>`);
|
||||
marker.bindPopup(`<b>${ib.nama_ibadah}</b><br>
|
||||
Jenis Rumah Ibadah: ${ib.jenis}<br>
|
||||
Jangkauan Bantuan: ${ib.radius_m} m
|
||||
<hr>
|
||||
<div style="display:flex; gap:6px;">
|
||||
${ROLE === 'admin' || ROLE === 'operator' ? `
|
||||
<button onclick="editIbadah(${ib.id})"
|
||||
style="flex:1; padding:6px; background:#2980b9; color:white;
|
||||
border:none; border-radius:4px; cursor:pointer; font-size:12px;">
|
||||
<i class="fa-solid fa-pen-to-square"></i> Edit
|
||||
</button>
|
||||
` : ''}
|
||||
${ROLE === 'admin' ? `
|
||||
<button onclick="hapusIbadah(${ib.id})"
|
||||
style="flex:1; padding:6px; background:none; color:red;
|
||||
border:1px solid red; border-radius:4px; cursor:pointer; font-size:12px;">
|
||||
<i class="fa-solid fa-trash"></i> Hapus
|
||||
</button>
|
||||
` : ''}
|
||||
</div>`
|
||||
);
|
||||
|
||||
marker.on('dragend', function(e) {
|
||||
let pos = e.target.getLatLng();
|
||||
@@ -225,13 +248,29 @@ function loadDB() {
|
||||
${statusOrtuTeks}
|
||||
<b>Keterangan:</b> ${rumah.keterangan || '-'}<br>
|
||||
<hr style="margin: 5px 0;">
|
||||
<button onclick="hapusPrasejahtera(${rumah.id})" style="color: red; width: 100%; cursor:pointer; border:none; background:none;">
|
||||
<i class="fa-solid fa-trash"></i> Hapus Data
|
||||
</button>
|
||||
<div style="display:flex; gap:6px;">
|
||||
${ROLE === 'admin' || ROLE === 'operator' ? `
|
||||
<button onclick="editPrasejahtera(${rumah.id})"
|
||||
style="flex:1; padding:6px; background:#2980b9; color:white;
|
||||
border:none; border-radius:4px; cursor:pointer; font-size:12px;">
|
||||
<i class="fa-solid fa-pen-to-square"></i> Edit
|
||||
</button>
|
||||
` : ''}
|
||||
${ROLE === 'admin' ? `
|
||||
<button onclick="hapusPrasejahtera(${rumah.id})"
|
||||
style="flex:1; padding:6px; background:none; color:red;
|
||||
border:1px solid red; border-radius:4px; cursor:pointer; font-size:12px;">
|
||||
<i class="fa-solid fa-trash"></i> Hapus
|
||||
</button>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
let marker = L.marker([rumah.lat, rumah.lng], { icon: ikonPrasejahtera, draggable: true })
|
||||
let marker = L.marker([rumah.lat, rumah.lng], {
|
||||
icon: ikonPrasejahtera,
|
||||
draggable: ROLE === 'admin' || ROLE === 'operator'
|
||||
})
|
||||
.addTo(layerPrasejahtera);
|
||||
marker.bindPopup(isiPopup);
|
||||
marker.on('dragend', function(e) {
|
||||
@@ -266,6 +305,8 @@ function refreshPeta() {
|
||||
|
||||
// --- EVENT KLIK PETA ---
|
||||
function onMapClick(e) {
|
||||
if (ROLE === 'viewer') return;
|
||||
|
||||
if (currentMode === 'point') {
|
||||
let formHtml = `
|
||||
<div style="width: 200px;">
|
||||
@@ -517,3 +558,220 @@ function toggleTerusan() {
|
||||
document.getElementById('grup_nominal_terusan').style.display = (ada === 'Ya') ? 'block' : 'none';
|
||||
if(ada === 'Tidak') document.getElementById('nominal_terusan').value = 0;
|
||||
}
|
||||
|
||||
// --- EDIT PRASEJAHTERA ---
|
||||
function editPrasejahtera(id) {
|
||||
fetch(`api/prasejahtera/get_prasejahtera.php?id=${id}`)
|
||||
.then(res => res.json())
|
||||
.then(d => {
|
||||
let formHtml = `
|
||||
<div style="width: 250px;">
|
||||
<h4 style="margin-top:0; border-bottom:1px solid #ddd; padding-bottom:5px;">
|
||||
<i class="fa-solid fa-pen-to-square"></i> Edit Data Prasejahtera
|
||||
</h4>
|
||||
|
||||
<label style="font-size:12px; font-weight:bold;">Nama Kepala Keluarga:</label>
|
||||
<input type="text" id="edit_nama_kk" value="${d.nama_kepala_keluarga}"
|
||||
style="width:100%; margin-bottom:8px; padding:4px;">
|
||||
|
||||
<label style="font-size:12px; font-weight:bold;">Jumlah Anak:</label>
|
||||
<input type="number" id="edit_jumlah_anak" value="${d.jumlah_anak}"
|
||||
style="width:100%; margin-bottom:8px; padding:4px;">
|
||||
|
||||
<label style="font-size:12px; font-weight:bold;">Umur Anak (pisahkan dgn koma):</label>
|
||||
<input type="text" id="edit_umur_anak" value="${d.umur_anak || ''}"
|
||||
placeholder="Contoh: 15, 12, 8"
|
||||
style="width:100%; margin-bottom:8px; padding:4px;">
|
||||
|
||||
<label style="font-size:12px; font-weight:bold;">Status Orang Tua:</label>
|
||||
<select id="edit_status_ortu" onchange="toggleEditStatusOrtu()"
|
||||
style="width:100%; margin-bottom:8px; padding:4px;">
|
||||
<option value="Bekerja" ${d.status_ortu === 'Bekerja' ? 'selected' : ''}>Bekerja</option>
|
||||
<option value="Pensiun" ${d.status_ortu === 'Pensiun' ? 'selected' : ''}>Pensiun</option>
|
||||
<option value="Meninggal" ${d.status_ortu === 'Meninggal' ? 'selected' : ''}>Meninggal Dunia</option>
|
||||
</select>
|
||||
|
||||
<div id="edit_grup_bekerja" style="display:${d.status_ortu === 'Bekerja' ? 'block' : 'none'};
|
||||
background:#e8f8f5; padding:5px; border-radius:4px; margin-bottom:8px;">
|
||||
<label style="font-size:12px; font-weight:bold;">Penghasilan/Bulan (Rp):</label>
|
||||
<input type="number" id="edit_penghasilan" value="${d.penghasilan || 0}"
|
||||
style="width:100%; padding:4px;">
|
||||
</div>
|
||||
|
||||
<div id="edit_grup_pensiun" style="display:${d.status_ortu === 'Pensiun' ? 'block' : 'none'};
|
||||
background:#fef9e7; padding:5px; border-radius:4px; margin-bottom:8px;">
|
||||
<label style="font-size:12px; font-weight:bold;">Ada Uang Pensiun?</label>
|
||||
<select id="edit_ada_pensiun" onchange="toggleEditPensiun()"
|
||||
style="width:100%; margin-bottom:5px; padding:4px;">
|
||||
<option value="Tidak" ${d.ada_pensiun === 'Tidak' ? 'selected' : ''}>Tidak Ada</option>
|
||||
<option value="Ya" ${d.ada_pensiun === 'Ya' ? 'selected' : ''}>Ya, Ada</option>
|
||||
</select>
|
||||
<div id="edit_grup_nominal_pensiun" style="display:${d.ada_pensiun === 'Ya' ? 'block' : 'none'};">
|
||||
<label style="font-size:12px; font-weight:bold;">Nominal Pensiun (Rp):</label>
|
||||
<input type="number" id="edit_nominal_pensiun" value="${d.nominal_pensiun || 0}"
|
||||
style="width:100%; padding:4px;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="edit_grup_meninggal" style="display:${d.status_ortu === 'Meninggal' ? 'block' : 'none'};
|
||||
background:#fdedec; padding:5px; border-radius:4px; margin-bottom:8px;">
|
||||
<label style="font-size:12px; font-weight:bold;">Ada Uang Terusan?</label>
|
||||
<select id="edit_ada_terusan" onchange="toggleEditTerusan()"
|
||||
style="width:100%; margin-bottom:5px; padding:4px;">
|
||||
<option value="Tidak" ${d.ada_terusan === 'Tidak' ? 'selected' : ''}>Tidak Ada</option>
|
||||
<option value="Ya" ${d.ada_terusan === 'Ya' ? 'selected' : ''}>Ya, Ada</option>
|
||||
</select>
|
||||
<div id="edit_grup_nominal_terusan" style="display:${d.ada_terusan === 'Ya' ? 'block' : 'none'};">
|
||||
<label style="font-size:12px; font-weight:bold;">Nominal Terusan (Rp):</label>
|
||||
<input type="number" id="edit_nominal_terusan" value="${d.nominal_terusan || 0}"
|
||||
style="width:100%; padding:4px;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label style="font-size:12px; font-weight:bold;">Keterangan Tambahan:</label>
|
||||
<textarea id="edit_keterangan" style="width:100%; margin-bottom:10px; padding:4px;">${d.keterangan || ''}</textarea>
|
||||
|
||||
<button onclick="simpanEditPrasejahtera(${id})"
|
||||
style="width:100%; padding:8px; background:#2980b9; color:white;
|
||||
border:none; border-radius:4px; font-weight:bold; cursor:pointer;">
|
||||
<i class="fa-solid fa-save"></i> Simpan Perubahan
|
||||
</button>
|
||||
</div>`;
|
||||
|
||||
// Ganti konten popup yang sudah terbuka dengan form edit
|
||||
daftarMarker['p_' + id].getPopup().setContent(formHtml);
|
||||
})
|
||||
.catch(() => Toast.fire({ icon: 'error', title: 'Gagal memuat data!' }));
|
||||
}
|
||||
|
||||
function toggleEditStatusOrtu() {
|
||||
let status = document.getElementById('edit_status_ortu').value;
|
||||
document.getElementById('edit_grup_bekerja').style.display = status === 'Bekerja' ? 'block' : 'none';
|
||||
document.getElementById('edit_grup_pensiun').style.display = status === 'Pensiun' ? 'block' : 'none';
|
||||
document.getElementById('edit_grup_meninggal').style.display = status === 'Meninggal' ? 'block' : 'none';
|
||||
if (status !== 'Bekerja') document.getElementById('edit_penghasilan').value = 0;
|
||||
if (status !== 'Pensiun') { document.getElementById('edit_ada_pensiun').value = 'Tidak'; toggleEditPensiun(); }
|
||||
if (status !== 'Meninggal') { document.getElementById('edit_ada_terusan').value = 'Tidak'; toggleEditTerusan(); }
|
||||
}
|
||||
|
||||
function toggleEditPensiun() {
|
||||
let ada = document.getElementById('edit_ada_pensiun').value;
|
||||
document.getElementById('edit_grup_nominal_pensiun').style.display = ada === 'Ya' ? 'block' : 'none';
|
||||
if (ada === 'Tidak') document.getElementById('edit_nominal_pensiun').value = 0;
|
||||
}
|
||||
|
||||
function toggleEditTerusan() {
|
||||
let ada = document.getElementById('edit_ada_terusan').value;
|
||||
document.getElementById('edit_grup_nominal_terusan').style.display = ada === 'Ya' ? 'block' : 'none';
|
||||
if (ada === 'Tidak') document.getElementById('edit_nominal_terusan').value = 0;
|
||||
}
|
||||
|
||||
function simpanEditPrasejahtera(id) {
|
||||
let nama_kk = document.getElementById('edit_nama_kk').value.trim();
|
||||
if (!nama_kk) {
|
||||
Toast.fire({ icon: 'warning', title: 'Nama Kepala Keluarga wajib diisi!' });
|
||||
return;
|
||||
}
|
||||
|
||||
let dataKirim = {
|
||||
id: id,
|
||||
nama_kk: nama_kk,
|
||||
jumlah_anak: parseInt(document.getElementById('edit_jumlah_anak').value) || 0,
|
||||
umur_anak: document.getElementById('edit_umur_anak').value,
|
||||
status_ortu: document.getElementById('edit_status_ortu').value,
|
||||
penghasilan: parseInt(document.getElementById('edit_penghasilan').value) || 0,
|
||||
ada_pensiun: document.getElementById('edit_ada_pensiun').value,
|
||||
nominal_pensiun: parseInt(document.getElementById('edit_nominal_pensiun').value) || 0,
|
||||
ada_terusan: document.getElementById('edit_ada_terusan').value,
|
||||
nominal_terusan: parseInt(document.getElementById('edit_nominal_terusan').value) || 0,
|
||||
keterangan: document.getElementById('edit_keterangan').value
|
||||
};
|
||||
|
||||
fetch('api/prasejahtera/update_prasejahtera.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(dataKirim)
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
Toast.fire({ icon: 'success', title: 'Data Berhasil Diperbarui!' });
|
||||
map.closePopup();
|
||||
refreshPeta();
|
||||
} else {
|
||||
Toast.fire({ icon: 'error', title: 'Gagal: ' + (data.message || 'Error') });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// --- EDIT IBADAH ---
|
||||
function editIbadah(id) {
|
||||
fetch(`api/rumahibadah/get_ibadah.php?id=${id}`)
|
||||
.then(res => res.json())
|
||||
.then(d => {
|
||||
let jenisOptions = ['Masjid', 'Gereja', 'Vihara', 'Pura', 'Klenteng'].map(j =>
|
||||
`<option value="${j}" ${d.jenis === j ? 'selected' : ''}>${j}</option>`
|
||||
).join('');
|
||||
|
||||
let formHtml = `
|
||||
<div style="width: 220px;">
|
||||
<h4 style="margin-top:0; border-bottom:1px solid #ddd; padding-bottom:5px;">
|
||||
<i class="fa-solid fa-pen-to-square"></i> Edit Rumah Ibadah
|
||||
</h4>
|
||||
|
||||
<label style="font-size:12px; font-weight:bold;">Jenis:</label>
|
||||
<select id="edit_jenis_ibadah" style="width:100%; margin-bottom:8px; padding:6px; box-sizing:border-box;">
|
||||
${jenisOptions}
|
||||
</select>
|
||||
|
||||
<label style="font-size:12px; font-weight:bold;">Nama Rumah Ibadah:</label>
|
||||
<input type="text" id="edit_nama_ibadah" value="${d.nama_ibadah}"
|
||||
style="width:100%; margin-bottom:8px; padding:6px; box-sizing:border-box;">
|
||||
|
||||
<label style="font-size:12px; font-weight:bold;">Radius Bantuan (meter):</label>
|
||||
<input type="number" id="edit_radius_ibadah" value="${d.radius_m}"
|
||||
min="50" max="5000"
|
||||
style="width:100%; margin-bottom:12px; padding:6px; box-sizing:border-box;">
|
||||
|
||||
<button onclick="simpanEditIbadah(${id})"
|
||||
style="width:100%; padding:8px; background:#8e44ad; color:white;
|
||||
border:none; border-radius:4px; font-weight:bold; cursor:pointer;">
|
||||
<i class="fa-solid fa-save"></i> Simpan Perubahan
|
||||
</button>
|
||||
</div>`;
|
||||
|
||||
daftarMarker['ib_' + id].getPopup().setContent(formHtml);
|
||||
})
|
||||
.catch(() => Toast.fire({ icon: 'error', title: 'Gagal memuat data!' }));
|
||||
}
|
||||
|
||||
function simpanEditIbadah(id) {
|
||||
let nama = document.getElementById('edit_nama_ibadah').value.trim();
|
||||
if (!nama) {
|
||||
Toast.fire({ icon: 'warning', title: 'Nama Rumah Ibadah wajib diisi!' });
|
||||
return;
|
||||
}
|
||||
|
||||
let dataKirim = {
|
||||
id: id,
|
||||
nama_ibadah: nama,
|
||||
jenis: document.getElementById('edit_jenis_ibadah').value,
|
||||
radius_m: parseInt(document.getElementById('edit_radius_ibadah').value)
|
||||
};
|
||||
|
||||
fetch('api/rumahibadah/update_ibadah.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(dataKirim)
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
Toast.fire({ icon: 'success', title: 'Rumah Ibadah Diperbarui!' });
|
||||
map.closePopup();
|
||||
refreshPeta();
|
||||
} else {
|
||||
Toast.fire({ icon: 'error', title: 'Gagal: ' + (data.message || 'Error') });
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pastikan user sudah login.
|
||||
* Kalau belum, redirect ke login.php
|
||||
*/
|
||||
function requireLogin() {
|
||||
if (!isset($_SESSION['user'])) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pastikan user punya role tertentu.
|
||||
* Kalau tidak, kembalikan response JSON error (untuk endpoint API)
|
||||
*/
|
||||
function requireRole(...$roles) {
|
||||
requireLogin();
|
||||
if (!in_array($_SESSION['role'], $roles)) {
|
||||
http_response_code(403);
|
||||
echo json_encode(["status" => "error", "message" => "Akses ditolak."]);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: cek role tanpa exit, untuk dipakai di kondisi if
|
||||
*/
|
||||
function hasRole(...$roles) {
|
||||
return isset($_SESSION['role']) && in_array($_SESSION['role'], $roles);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Sistem Pemetaan</title>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.css" />
|
||||
|
||||
<link rel="stylesheet" href="assets/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="sidebar">
|
||||
<h3>Menu Pemetaan</h3>
|
||||
|
||||
<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>
|
||||
|
||||
<div id="map-container">
|
||||
<div id="map"></div>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.min.js"></script>
|
||||
<script src="assets/js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
session_start();
|
||||
$isLoggedIn = isset($_SESSION['user']);
|
||||
$role = $isLoggedIn ? $_SESSION['role'] : 'viewer';
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Sistem Pemetaan</title>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.css" />
|
||||
<link rel="stylesheet" href="assets/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="sidebar">
|
||||
<h3>Menu Pemetaan</h3>
|
||||
|
||||
<?php if ($isLoggedIn): ?>
|
||||
<!-- Tampil kalau sudah login -->
|
||||
<div class="user-info">
|
||||
<i class="fa-solid fa-circle-user"></i>
|
||||
<span><?= htmlspecialchars($_SESSION['nama']) ?></span>
|
||||
<small><?= ucfirst($role) ?></small>
|
||||
</div>
|
||||
|
||||
<?php if (in_array($role, ['admin', 'operator'])): ?>
|
||||
<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'): ?>
|
||||
<a href="users.php" class="menu-link">
|
||||
<i class="fa-solid fa-users-gear"></i> Kelola User
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<a href="logout.php" class="btn-logout">
|
||||
<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 id="map-container">
|
||||
<div id="map"></div>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
<script src="https://unpkg.com/@geoman-io/leaflet-geoman-free@latest/dist/leaflet-geoman.min.js"></script>
|
||||
|
||||
<!-- Pass role ke JavaScript -->
|
||||
<script>
|
||||
const ROLE = '<?= $role ?>';
|
||||
</script>
|
||||
|
||||
<script src="assets/js/script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// Kalau sudah login, langsung redirect ke peta
|
||||
if (isset($_SESSION['user'])) {
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$error = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
||||
|
||||
$username = trim($_POST['username']);
|
||||
$password = trim($_POST['password']);
|
||||
|
||||
if ($username && $password) {
|
||||
$stmt = $conn->prepare("SELECT id, nama, username, password, role FROM users WHERE username = ?");
|
||||
$stmt->bind_param("s", $username);
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result();
|
||||
$user = $result->fetch_assoc();
|
||||
|
||||
if ($user && password_verify($password, $user['password'])) {
|
||||
// Login berhasil
|
||||
$_SESSION['user'] = $user['id'];
|
||||
$_SESSION['nama'] = $user['nama'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
} else {
|
||||
$error = "Username atau password salah.";
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
} else {
|
||||
$error = "Username dan password wajib diisi.";
|
||||
}
|
||||
|
||||
$conn->close();
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Login - Sistem Pemetaan</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
background: #f0f4f8;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.login-card {
|
||||
background: white;
|
||||
padding: 40px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
||||
width: 100%;
|
||||
max-width: 380px;
|
||||
}
|
||||
|
||||
.login-card h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 8px;
|
||||
color: #1B2A4A;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.login-card .subtitle {
|
||||
text-align: center;
|
||||
color: #888;
|
||||
font-size: 13px;
|
||||
margin-bottom: 28px;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #444;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.input-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.input-wrapper i {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #aaa;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.input-wrapper input {
|
||||
width: 100%;
|
||||
padding: 10px 12px 10px 36px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
transition: border-color 0.2s;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.input-wrapper input:focus {
|
||||
border-color: #1B2A4A;
|
||||
}
|
||||
|
||||
.error-msg {
|
||||
background: #fdecea;
|
||||
color: #c0392b;
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background: #1B2A4A;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.btn-submit:hover {
|
||||
background: #253d6e;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-top: 16px;
|
||||
font-size: 13px;
|
||||
color: #888;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.back-link:hover {
|
||||
color: #1B2A4A;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-card">
|
||||
<h2><i class="fa-solid fa-map-location-dot" style="color:#1B2A4A;"></i> Sistem Pemetaan Kemiskinan</h2>
|
||||
<p class="subtitle">Masuk untuk mengelola data peta</p>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="error-msg">
|
||||
<i class="fa-solid fa-circle-exclamation"></i>
|
||||
<?= htmlspecialchars($error) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div class="form-group">
|
||||
<label>Username</label>
|
||||
<div class="input-wrapper">
|
||||
<i class="fa-solid fa-user"></i>
|
||||
<input type="text" name="username" placeholder="Masukkan username"
|
||||
value="<?= htmlspecialchars($_POST['username'] ?? '') ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<div class="input-wrapper">
|
||||
<i class="fa-solid fa-lock"></i>
|
||||
<input type="password" name="password" placeholder="Masukkan password" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit">
|
||||
<i class="fa-solid fa-right-to-bracket"></i> Login
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<a href="index.php" class="back-link">
|
||||
<i class="fa-solid fa-arrow-left"></i> Kembali ke Peta
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
session_start();
|
||||
session_destroy();
|
||||
header("Location: index.php");
|
||||
exit;
|
||||
?>
|
||||
@@ -0,0 +1,399 @@
|
||||
<?php
|
||||
require_once 'auth.php';
|
||||
requireLogin();
|
||||
requireRole('admin');
|
||||
|
||||
$conn = new mysqli("localhost", "root", "", "webgis");
|
||||
$error = '';
|
||||
$success = '';
|
||||
|
||||
// --- TAMBAH USER ---
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'tambah') {
|
||||
$nama = trim($_POST['nama']);
|
||||
$username = trim($_POST['username']);
|
||||
$password = trim($_POST['password']);
|
||||
$role = $_POST['role'];
|
||||
|
||||
if (!$nama || !$username || !$password || !in_array($role, ['admin', 'operator'])) {
|
||||
$error = "Semua field wajib diisi dengan benar.";
|
||||
} else {
|
||||
// Cek apakah username sudah ada
|
||||
$cek = $conn->prepare("SELECT id FROM users WHERE username = ?");
|
||||
$cek->bind_param("s", $username);
|
||||
$cek->execute();
|
||||
$cek->store_result();
|
||||
|
||||
if ($cek->num_rows > 0) {
|
||||
$error = "Username <b>$username</b> sudah digunakan.";
|
||||
} else {
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
$stmt = $conn->prepare("INSERT INTO users (nama, username, password, role) VALUES (?, ?, ?, ?)");
|
||||
$stmt->bind_param("ssss", $nama, $username, $hash, $role);
|
||||
if ($stmt->execute()) {
|
||||
$success = "User <b>$username</b> berhasil ditambahkan.";
|
||||
} else {
|
||||
$error = "Gagal menyimpan user: " . $stmt->error;
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
$cek->close();
|
||||
}
|
||||
}
|
||||
|
||||
// --- HAPUS USER ---
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'hapus') {
|
||||
$id = (int) $_POST['id'];
|
||||
|
||||
// Tidak boleh hapus diri sendiri
|
||||
if ($id === (int) $_SESSION['user']) {
|
||||
$error = "Tidak bisa menghapus akun yang sedang aktif.";
|
||||
} else {
|
||||
$stmt = $conn->prepare("DELETE FROM users WHERE id = ?");
|
||||
$stmt->bind_param("i", $id);
|
||||
if ($stmt->execute()) {
|
||||
$success = "User berhasil dihapus.";
|
||||
} else {
|
||||
$error = "Gagal menghapus user.";
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
}
|
||||
|
||||
// --- AMBIL SEMUA USER ---
|
||||
$users = $conn->query("SELECT id, nama, username, role, created_at FROM users ORDER BY created_at DESC");
|
||||
$conn->close();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Kelola User - Sistem Pemetaan</title>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', sans-serif;
|
||||
background: #f0f4f8;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* NAVBAR */
|
||||
.navbar {
|
||||
background: #1B2A4A;
|
||||
color: white;
|
||||
padding: 14px 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.navbar h1 {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
opacity: 0.85;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
|
||||
.navbar a:hover { opacity: 1; }
|
||||
|
||||
/* CONTAINER */
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 32px auto;
|
||||
padding: 0 20px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 320px;
|
||||
gap: 24px;
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
/* CARD */
|
||||
.card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 12px rgba(0,0,0,0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background: #1B2A4A;
|
||||
color: white;
|
||||
padding: 16px 20px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.card-body { padding: 20px; }
|
||||
|
||||
/* ALERT */
|
||||
.alert {
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.alert-success { background: #eafaf1; color: #1e8449; }
|
||||
.alert-error { background: #fdecea; color: #c0392b; }
|
||||
|
||||
/* TABEL */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
thead th {
|
||||
background: #f0f4f8;
|
||||
color: #555;
|
||||
font-weight: 600;
|
||||
padding: 10px 14px;
|
||||
text-align: left;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
border-bottom: 1px solid #f0f4f8;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
tbody tr:hover { background: #fafbfc; }
|
||||
|
||||
tbody td {
|
||||
padding: 12px 14px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 3px 10px;
|
||||
border-radius: 20px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.badge-admin { background: #1B2A4A; color: white; }
|
||||
.badge-operator { background: #e8f4fd; color: #2471a3; }
|
||||
|
||||
.badge-me {
|
||||
font-size: 10px;
|
||||
background: #eafaf1;
|
||||
color: #1e8449;
|
||||
padding: 2px 6px;
|
||||
border-radius: 10px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.btn-hapus {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #e74c3c;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
|
||||
.btn-hapus:hover { background: #fdecea; }
|
||||
.btn-hapus:disabled { opacity: 0.3; cursor: not-allowed; }
|
||||
|
||||
/* FORM */
|
||||
.form-group { margin-bottom: 14px; }
|
||||
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #555;
|
||||
margin-bottom: 5px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.4px;
|
||||
}
|
||||
|
||||
.form-group input,
|
||||
.form-group select {
|
||||
width: 100%;
|
||||
padding: 9px 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
transition: border-color 0.2s;
|
||||
}
|
||||
|
||||
.form-group input:focus,
|
||||
.form-group select:focus {
|
||||
border-color: #1B2A4A;
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
width: 100%;
|
||||
padding: 11px;
|
||||
background: #1B2A4A;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.btn-submit:hover { background: #253d6e; }
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.container { grid-template-columns: 1fr; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar">
|
||||
<h1><i class="fa-solid fa-users-gear"></i> Kelola User</h1>
|
||||
<a href="index.php">
|
||||
<i class="fa-solid fa-map-location-dot"></i> Kembali ke Peta
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- TABEL DAFTAR USER -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<i class="fa-solid fa-list"></i> Daftar User
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-error">
|
||||
<i class="fa-solid fa-circle-exclamation"></i>
|
||||
<?= $error ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success">
|
||||
<i class="fa-solid fa-circle-check"></i>
|
||||
<?= $success ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Nama</th>
|
||||
<th>Username</th>
|
||||
<th>Role</th>
|
||||
<th>Dibuat</th>
|
||||
<th>Aksi</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php $no = 1; while ($u = $users->fetch_assoc()): ?>
|
||||
<tr>
|
||||
<td><?= $no++ ?></td>
|
||||
<td>
|
||||
<?= htmlspecialchars($u['nama']) ?>
|
||||
<?php if ($u['id'] == $_SESSION['user']): ?>
|
||||
<span class="badge-me">Anda</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($u['username']) ?></td>
|
||||
<td>
|
||||
<span class="badge badge-<?= $u['role'] ?>">
|
||||
<?= ucfirst($u['role']) ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?= date('d M Y', strtotime($u['created_at'])) ?></td>
|
||||
<td>
|
||||
<form method="POST" onsubmit="return konfirmasiHapus(this)">
|
||||
<input type="hidden" name="action" value="hapus">
|
||||
<input type="hidden" name="id" value="<?= $u['id'] ?>">
|
||||
<button type="submit" class="btn-hapus"
|
||||
<?= $u['id'] == $_SESSION['user'] ? 'disabled title="Tidak bisa hapus akun sendiri"' : '' ?>>
|
||||
<i class="fa-solid fa-trash"></i> Hapus
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endwhile; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FORM TAMBAH USER -->
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<i class="fa-solid fa-user-plus"></i> Tambah User Baru
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST">
|
||||
<input type="hidden" name="action" value="tambah">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Nama Lengkap</label>
|
||||
<input type="text" name="nama" placeholder="Contoh: Budi Santoso" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Username</label>
|
||||
<input type="text" name="username" placeholder="Contoh: budi123" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<input type="password" name="password" placeholder="Min. 6 karakter" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Role</label>
|
||||
<select name="role">
|
||||
<option value="operator">Operator</option>
|
||||
<option value="admin">Admin</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-submit">
|
||||
<i class="fa-solid fa-user-plus"></i> Tambah User
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function konfirmasiHapus(form) {
|
||||
return confirm("Yakin ingin menghapus user ini?");
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -59,9 +59,9 @@
|
||||
<p style="text-align: center;">Nama: Muhammad Fauzi | NIM: D1041231083</p>
|
||||
|
||||
<ul class="link-list">
|
||||
<li><a href="./Pertemuan01/index.html">Tugas Pertemuan 1</a></li>
|
||||
<li><a href="./Pertemuan02/index.html">Tugas Pertemuan 2</a></li>
|
||||
<li><a href="./WebGISPovertyMapping/index.html">Tugas Poverty Mapping</a></li>
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user