First commit / commit pertama

This commit is contained in:
Mr.Haruna
2026-06-13 11:24:58 +07:00
commit 522c4f7200
166 changed files with 13326 additions and 0 deletions
+235
View File
@@ -0,0 +1,235 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/auth_check.php';
requireAnyRole(['operator']);
$pdo = Database::getConnection();
$rows = $pdo->query(
"SELECT id, username, email, role, is_active, wilayah_tugas, nama_lengkap, last_login, created_at
FROM users ORDER BY id ASC"
)->fetchAll();
$wilayahList = $pdo->query("SELECT nama FROM wilayah ORDER BY nama")->fetchAll();
$pageTitle = 'Kelola Users';
$activeNav = 'users';
require_once __DIR__ . '/partials/header.php';
// Helper badge per role
function roleBadge(string $role): string {
return match ($role) {
'operator' => '<span class="badge badge-danger">🛠️ Operator</span>',
'pimpinan' => '<span class="badge" style="background:#EDE9FE;color:#6D28D9;">📊 Pimpinan</span>',
'enumerator' => '<span class="badge badge-info">📋 Enumerator</span>',
'publik' => '<span class="badge" style="background:#F3F4F6;color:#6B7280;">🌐 Publik</span>',
default => htmlspecialchars($role),
};
}
?>
<div class="page-header">
<div class="breadcrumb"><span>Operator</span><span class="sep">/</span><span>Users</span></div>
<h1>👤 Manajemen User Sistem</h1>
<p>Kelola akun 4 peran: Publik, Enumerator, Operator, dan Pimpinan (KF-02 / KF-03).</p>
</div>
<div class="page-toolbar">
<div class="search-box">
<i class="fas fa-search search-icon"></i>
<input type="text" id="searchInput" placeholder="Cari user..." oninput="filterTable('searchInput','usersTable')">
</div>
<button class="btn btn-primary" onclick="openModal('modalTambah')">
<i class="fas fa-plus"></i> Tambah User
</button>
</div>
<div class="table-wrap">
<table class="data-table" id="usersTable">
<thead><tr>
<th>#</th><th>Username</th><th>Nama Lengkap</th><th>Email</th><th>Role</th>
<th>Wilayah</th><th>Status</th><th>Login Terakhir</th><th>Aksi</th>
</tr></thead>
<tbody>
<?php foreach ($rows as $i => $r): ?>
<tr>
<td style="color:var(--text-muted)"><?= $i+1 ?></td>
<td><strong><?= htmlspecialchars($r['username']) ?></strong></td>
<td><?= htmlspecialchars($r['nama_lengkap'] ?: '-') ?></td>
<td style="font-size:0.82rem;color:var(--text-muted)"><?= htmlspecialchars($r['email'] ?: '-') ?></td>
<td><?= roleBadge($r['role']) ?></td>
<td style="font-size:0.82rem"><?= htmlspecialchars($r['wilayah_tugas'] ?: '-') ?></td>
<td>
<?php if ((int)$r['is_active'] === 1): ?>
<span class="badge badge-success">Aktif</span>
<?php else: ?>
<span class="badge badge-danger">Nonaktif</span>
<?php endif; ?>
</td>
<td style="color:var(--text-muted); font-size:0.78rem;">
<?= $r['last_login'] ? date('d M Y H:i', strtotime($r['last_login'])) : 'Belum pernah' ?>
</td>
<td><div class="actions">
<button class="btn btn-ghost btn-sm btn-icon" onclick='editRow(<?= json_encode($r, JSON_HEX_APOS|JSON_HEX_QUOT) ?>)' title="Edit">
<i class="fas fa-edit"></i>
</button>
<button class="btn btn-danger btn-sm btn-icon" onclick="hapus(<?= $r['id'] ?>,'<?= addslashes($r['username']) ?>')" title="Hapus">
<i class="fas fa-trash"></i>
</button>
</div></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- Modal Tambah -->
<div class="modal-overlay" id="modalTambah">
<div class="modal">
<div class="modal-header">
<span class="modal-title">👤 Tambah User Baru</span>
<button class="modal-close" onclick="closeModal('modalTambah')">×</button>
</div>
<form id="formTambah">
<div class="form-group"><label class="form-label">Username *</label><input type="text" id="tUsername" class="form-control" placeholder="username unik" required></div>
<div class="form-group"><label class="form-label">Nama Lengkap</label><input type="text" id="tNama" class="form-control" placeholder="Nama lengkap"></div>
<div class="form-group"><label class="form-label">Email</label><input type="email" id="tEmail" class="form-control" placeholder="email@contoh.id"></div>
<div class="form-group"><label class="form-label">Role *</label>
<select id="tRole" class="form-control" onchange="toggleWilayah('t')">
<option value="enumerator">📋 Enumerator</option>
<option value="operator">🛠️ Operator</option>
<option value="pimpinan">📊 Pimpinan</option>
<option value="publik">🌐 Publik</option>
</select>
</div>
<div class="form-group" id="tWilayahGroup"><label class="form-label">Wilayah Tugas</label>
<select id="tWilayah" class="form-control"><option value="">- pilih kelurahan -</option>
<?php foreach ($wilayahList as $w): ?><option value="<?= htmlspecialchars($w['nama']) ?>"><?= htmlspecialchars($w['nama']) ?></option><?php endforeach; ?>
</select></div>
<div class="form-group"><label class="form-label">Password *</label><input type="password" id="tPassword" class="form-control" placeholder="Minimal 6 karakter" required minlength="6"></div>
</form>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('modalTambah')">Batal</button>
<button class="btn btn-primary" onclick="simpan()"><i class="fas fa-save"></i> Simpan</button>
</div>
</div>
</div>
<!-- Modal Edit -->
<div class="modal-overlay" id="modalEdit">
<div class="modal">
<div class="modal-header">
<span class="modal-title">✏️ Edit User</span>
<button class="modal-close" onclick="closeModal('modalEdit')">×</button>
</div>
<input type="hidden" id="editId">
<div class="form-group"><label class="form-label">Username *</label><input type="text" id="editUsername" class="form-control" required></div>
<div class="form-group"><label class="form-label">Nama Lengkap</label><input type="text" id="editNama" class="form-control"></div>
<div class="form-group"><label class="form-label">Email</label><input type="email" id="editEmail" class="form-control"></div>
<div class="form-group"><label class="form-label">Role *</label>
<select id="editRole" class="form-control" onchange="toggleWilayah('edit')">
<option value="enumerator">📋 Enumerator</option>
<option value="operator">🛠️ Operator</option>
<option value="pimpinan">📊 Pimpinan</option>
<option value="publik">🌐 Publik</option>
</select>
</div>
<div class="form-group" id="editWilayahGroup"><label class="form-label">Wilayah Tugas</label>
<select id="editWilayah" class="form-control"><option value="">- pilih kelurahan -</option>
<?php foreach ($wilayahList as $w): ?><option value="<?= htmlspecialchars($w['nama']) ?>"><?= htmlspecialchars($w['nama']) ?></option><?php endforeach; ?>
</select></div>
<div class="form-group"><label class="form-label">Status</label>
<select id="editActive" class="form-control">
<option value="1">Aktif</option>
<option value="0">Nonaktif</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Password Baru</label>
<input type="password" id="editPassword" class="form-control" placeholder="Kosongkan jika tidak diubah" minlength="6">
</div>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('modalEdit')">Batal</button>
<button class="btn btn-primary" onclick="update()"><i class="fas fa-save"></i> Perbarui</button>
</div>
</div>
</div>
<?php $extraScript = <<<'JS'
<script>
const API = APP_BASE + '/api/users.php';
// Wilayah tugas hanya relevan untuk enumerator
function toggleWilayah(prefix) {
const role = document.getElementById(prefix + 'Role').value;
const group = document.getElementById(prefix + 'WilayahGroup');
group.style.display = (role === 'enumerator') ? 'block' : 'none';
}
function editRow(r) {
document.getElementById('editId').value = r.id;
document.getElementById('editUsername').value = r.username;
document.getElementById('editNama').value = r.nama_lengkap || '';
document.getElementById('editEmail').value = r.email || '';
document.getElementById('editRole').value = r.role;
document.getElementById('editWilayah').value = r.wilayah_tugas || '';
document.getElementById('editActive').value = String(r.is_active);
document.getElementById('editPassword').value = '';
toggleWilayah('edit');
openModal('modalEdit');
}
async function simpan() {
const u = document.getElementById('tUsername').value.trim();
const p = document.getElementById('tPassword').value;
if (!u) return showToast('Username wajib!', 'error');
if (p.length < 6) return showToast('Password minimal 6 karakter!', 'error');
const res = await fetch(API, {
method: 'POST', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: u,
nama_lengkap: document.getElementById('tNama').value,
email: document.getElementById('tEmail').value,
role: document.getElementById('tRole').value,
wilayah_tugas: document.getElementById('tWilayah').value,
password: p
})
});
const d = await res.json();
if (d.status === 'success') { showToast('User berhasil ditambahkan!'); setTimeout(() => location.reload(), 900); }
else showToast(d.message || 'Gagal', 'error');
}
async function update() {
const id = document.getElementById('editId').value;
const u = document.getElementById('editUsername').value.trim();
const p = document.getElementById('editPassword').value;
if (!u) return showToast('Username wajib!', 'error');
if (p && p.length < 6) return showToast('Password minimal 6 karakter!', 'error');
const body = {
username: u,
nama_lengkap: document.getElementById('editNama').value,
email: document.getElementById('editEmail').value,
role: document.getElementById('editRole').value,
wilayah_tugas: document.getElementById('editWilayah').value,
is_active: document.getElementById('editActive').value
};
if (p) body.password = p;
const res = await fetch(API + '?id=' + id, {
method: 'PUT', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body)
});
const d = await res.json();
if (d.status === 'success') { showToast('User diperbarui!'); setTimeout(() => location.reload(), 900); }
else showToast(d.message || 'Gagal', 'error');
}
async function hapus(id, username) {
if (id == 1) return showToast('Akun utama (ID=1) tidak dapat dihapus!', 'error');
if (!confirm(`Hapus user "${username}"?`)) return;
const res = await fetch(API + '?id=' + id, { method: 'DELETE' });
const d = await res.json();
if (d.status === 'success') { showToast('User dihapus!'); setTimeout(() => location.reload(), 900); }
else showToast(d.message || 'Gagal', 'error');
}
toggleWilayah('t');
</script>
JS; ?>
<?php require_once __DIR__ . '/partials/footer.php'; ?>