feat: implement full authentication system and CRUD APIs for users, rumah ibadah, and penduduk miskin with database updates.
This commit is contained in:
@@ -0,0 +1,369 @@
|
||||
// --- Fitur Autentikasi dan Manajemen User (RBAC) ---
|
||||
|
||||
(function() {
|
||||
window.currentUser = null;
|
||||
|
||||
// Elements
|
||||
const authWidget = document.getElementById('authWidget');
|
||||
const loginModal = document.getElementById('loginModal');
|
||||
const loginUsernameInput = document.getElementById('loginUsername');
|
||||
const loginPasswordInput = document.getElementById('loginPassword');
|
||||
const loginSubmitBtn = document.getElementById('loginSubmitBtn');
|
||||
const loginErrorMsg = document.getElementById('loginErrorMsg');
|
||||
const closeLoginModal = document.getElementById('closeLoginModal');
|
||||
|
||||
// User Management Modal Elements
|
||||
const userManagementModal = document.getElementById('userManagementModal');
|
||||
const closeUserManagementModal = document.getElementById('closeUserManagementModal');
|
||||
const menuUsersBtn = document.getElementById('menuUsers');
|
||||
const userTableBody = document.getElementById('userTableBody');
|
||||
const btnSaveUser = document.getElementById('btnSaveUser');
|
||||
const btnCancelUserEdit = document.getElementById('btnCancelUserEdit');
|
||||
const userFormTitle = document.getElementById('userFormTitle');
|
||||
|
||||
const manageUserId = document.getElementById('manageUserId');
|
||||
const manageUsername = document.getElementById('manageUsername');
|
||||
const managePassword = document.getElementById('managePassword');
|
||||
const manageRole = document.getElementById('manageRole');
|
||||
const manageIbadahId = document.getElementById('manageIbadahId');
|
||||
const manageIbadahGroup = document.getElementById('manageIbadahGroup');
|
||||
|
||||
// Startup Session Check
|
||||
function checkSession() {
|
||||
fetch('api/check_session.php')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success' && data.isLoggedIn) {
|
||||
window.currentUser = data.data;
|
||||
} else {
|
||||
window.currentUser = null;
|
||||
}
|
||||
updateAuthUI();
|
||||
refreshAllLayers();
|
||||
})
|
||||
.catch(err => {
|
||||
console.error("Session check failed:", err);
|
||||
window.currentUser = null;
|
||||
updateAuthUI();
|
||||
});
|
||||
}
|
||||
|
||||
// Update UI based on logged-in state
|
||||
function updateAuthUI() {
|
||||
if (!authWidget) return;
|
||||
|
||||
if (window.currentUser) {
|
||||
// Logged In state
|
||||
const roleLabel = window.currentUser.role === 'admin' ? 'Admin' : 'Pengelola';
|
||||
const extraLabel = window.currentUser.nama_ibadah ? ` - ${window.currentUser.nama_ibadah}` : '';
|
||||
|
||||
authWidget.innerHTML = `
|
||||
<div class="user-profile-pill">
|
||||
<div class="user-profile-info">
|
||||
<div class="user-profile-name">👤 ${escHtml(window.currentUser.username)}</div>
|
||||
<div class="user-profile-role">${roleLabel}${escHtml(extraLabel)}</div>
|
||||
</div>
|
||||
<button class="btn-profile-logout" id="authLogoutBtn" title="Logout">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('authLogoutBtn').addEventListener('click', logout);
|
||||
|
||||
// Show user management button in sidebar for Admin
|
||||
const adminDivider = document.getElementById('sidebarAdminDivider');
|
||||
if (window.currentUser.role === 'admin') {
|
||||
if (menuUsersBtn) menuUsersBtn.style.display = 'flex';
|
||||
if (adminDivider) adminDivider.style.display = 'block';
|
||||
} else {
|
||||
if (menuUsersBtn) menuUsersBtn.style.display = 'none';
|
||||
if (adminDivider) adminDivider.style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
// Logged Out state
|
||||
authWidget.innerHTML = `
|
||||
<button class="btn-login" id="authLoginBtn"><i class="fas fa-sign-in-alt"></i> Login</button>
|
||||
`;
|
||||
document.getElementById('authLoginBtn').addEventListener('click', showLoginModal);
|
||||
if (menuUsersBtn) menuUsersBtn.style.display = 'none';
|
||||
const adminDivider = document.getElementById('sidebarAdminDivider');
|
||||
if (adminDivider) adminDivider.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function refreshAllLayers() {
|
||||
if (typeof loadSpbu === 'function') loadSpbu();
|
||||
if (typeof loadJalan === 'function') loadJalan();
|
||||
if (typeof loadParsil === 'function') loadParsil();
|
||||
if (typeof loadRumahIbadah === 'function') loadRumahIbadah();
|
||||
if (typeof loadPendudukMiskin === 'function') loadPendudukMiskin();
|
||||
if (window.refreshActivePanel) window.refreshActivePanel();
|
||||
}
|
||||
|
||||
// Login Modals logic
|
||||
function showLoginModal() {
|
||||
loginUsernameInput.value = '';
|
||||
loginPasswordInput.value = '';
|
||||
loginErrorMsg.style.display = 'none';
|
||||
loginModal.classList.add('show');
|
||||
}
|
||||
|
||||
function hideLoginModal() {
|
||||
loginModal.classList.remove('show');
|
||||
}
|
||||
|
||||
if (closeLoginModal) {
|
||||
closeLoginModal.addEventListener('click', hideLoginModal);
|
||||
}
|
||||
|
||||
loginSubmitBtn.addEventListener('click', function() {
|
||||
const username = loginUsernameInput.value.trim();
|
||||
const password = loginPasswordInput.value;
|
||||
|
||||
if (!username || !password) {
|
||||
loginErrorMsg.textContent = 'Username dan password wajib diisi';
|
||||
loginErrorMsg.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
fetch('api/login.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ username, password })
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
window.currentUser = data.data;
|
||||
hideLoginModal();
|
||||
updateAuthUI();
|
||||
refreshAllLayers();
|
||||
showToast('Login berhasil', 'success');
|
||||
} else {
|
||||
loginErrorMsg.textContent = data.message || 'Login gagal';
|
||||
loginErrorMsg.style.display = 'block';
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
loginErrorMsg.textContent = 'Koneksi ke server terputus';
|
||||
loginErrorMsg.style.display = 'block';
|
||||
});
|
||||
});
|
||||
|
||||
function logout() {
|
||||
fetch('api/logout.php')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
window.currentUser = null;
|
||||
updateAuthUI();
|
||||
refreshAllLayers();
|
||||
showToast('Logout berhasil', 'success');
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err);
|
||||
showToast('Gagal logout', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// User Management Modal Logic
|
||||
if (menuUsersBtn) {
|
||||
menuUsersBtn.addEventListener('click', function() {
|
||||
userManagementModal.classList.add('show');
|
||||
loadUsers();
|
||||
populateIbadahDropdown();
|
||||
resetUserForm();
|
||||
});
|
||||
}
|
||||
|
||||
if (closeUserManagementModal) {
|
||||
closeUserManagementModal.addEventListener('click', function() {
|
||||
userManagementModal.classList.remove('show');
|
||||
});
|
||||
}
|
||||
|
||||
// Show/hide ibadah dropdown based on selected role in form
|
||||
if (manageRole) {
|
||||
manageRole.addEventListener('change', function() {
|
||||
if (this.value === 'admin') {
|
||||
manageIbadahGroup.style.display = 'none';
|
||||
manageIbadahId.value = '';
|
||||
} else {
|
||||
manageIbadahGroup.style.display = 'flex';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function populateIbadahDropdown() {
|
||||
if (!manageIbadahId) return;
|
||||
manageIbadahId.innerHTML = '<option value="">-- Pilih Rumah Ibadah --</option>';
|
||||
if (typeof ibadahDataList !== 'undefined') {
|
||||
ibadahDataList.forEach(ib => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = ib.id;
|
||||
opt.textContent = `${ib.jenis || '🕌'} ${ib.nama}`;
|
||||
manageIbadahId.appendChild(opt);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function loadUsers() {
|
||||
if (!userTableBody) return;
|
||||
userTableBody.innerHTML = '<tr><td colspan="4" style="text-align:center; padding:15px; color:#aaa;">Memuat user...</td></tr>';
|
||||
|
||||
fetch('api/users/read.php')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
userTableBody.innerHTML = '';
|
||||
if (data.data.length === 0) {
|
||||
userTableBody.innerHTML = '<tr><td colspan="4" style="text-align:center; padding:15px; color:#aaa;">Belum ada user</td></tr>';
|
||||
return;
|
||||
}
|
||||
data.data.forEach(user => {
|
||||
const tr = document.createElement('tr');
|
||||
tr.style.borderBottom = '1px solid #e2e8f0';
|
||||
|
||||
const roleBadge = user.role === 'admin'
|
||||
? '<span class="data-card-badge badge-red">Admin</span>'
|
||||
: '<span class="data-card-badge badge-blue">Pengelola</span>';
|
||||
|
||||
tr.innerHTML = `
|
||||
<td style="padding:10px 12px; font-weight:600;">${escHtml(user.username)}</td>
|
||||
<td style="padding:10px 12px;">${roleBadge}</td>
|
||||
<td style="padding:10px 12px; color:#64748b;">${escHtml(user.nama_ibadah)}</td>
|
||||
<td style="padding:10px 12px; text-align:center; display:flex; gap:6px; justify-content:center;">
|
||||
<button class="btn-card-action btn-card-edit" title="Edit User" onclick="editUser(${JSON.stringify(user).replace(/"/g, '"')})">
|
||||
<i class="fas fa-pen"></i>
|
||||
</button>
|
||||
<button class="btn-card-action btn-card-delete" title="Hapus User" onclick="deleteUser(${user.id})">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
`;
|
||||
userTableBody.appendChild(tr);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
userTableBody.innerHTML = '<tr><td colspan="4" style="text-align:center; padding:15px; color:#ef4444;">Gagal memuat user</td></tr>';
|
||||
});
|
||||
}
|
||||
|
||||
window.editUser = function(user) {
|
||||
userFormTitle.textContent = 'Edit Pengguna';
|
||||
manageUserId.value = user.id;
|
||||
manageUsername.value = user.username;
|
||||
managePassword.value = ''; // Password cleared in edit
|
||||
manageRole.value = user.role;
|
||||
|
||||
if (user.role === 'admin') {
|
||||
manageIbadahGroup.style.display = 'none';
|
||||
manageIbadahId.value = '';
|
||||
} else {
|
||||
manageIbadahGroup.style.display = 'flex';
|
||||
manageIbadahId.value = user.ibadah_id || '';
|
||||
}
|
||||
|
||||
btnCancelUserEdit.style.display = 'inline-block';
|
||||
};
|
||||
|
||||
window.deleteUser = function(id) {
|
||||
if (confirm('Apakah Anda yakin ingin menghapus user ini?')) {
|
||||
fetch('api/users/delete.php', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ id })
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
showToast(data.message, 'success');
|
||||
loadUsers();
|
||||
resetUserForm();
|
||||
} else {
|
||||
showToast(data.message || 'Gagal menghapus user', 'error');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
showToast('Koneksi terputus', 'error');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
btnSaveUser.addEventListener('click', function() {
|
||||
const id = manageUserId.value;
|
||||
const username = manageUsername.value.trim();
|
||||
const password = managePassword.value;
|
||||
const role = manageRole.value;
|
||||
const ibadah_id = manageIbadahId.value;
|
||||
|
||||
if (!username) {
|
||||
alert('Username wajib diisi');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!id && !password) {
|
||||
alert('Password wajib diisi untuk user baru');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = { username, role, ibadah_id };
|
||||
if (id) payload.id = id;
|
||||
if (password) payload.password = password;
|
||||
|
||||
const endpoint = id ? 'api/users/update.php' : 'api/users/create.php';
|
||||
|
||||
fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
showToast(data.message, 'success');
|
||||
loadUsers();
|
||||
resetUserForm();
|
||||
} else {
|
||||
alert(data.message || 'Gagal menyimpan user');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
alert('Koneksi terputus');
|
||||
});
|
||||
});
|
||||
|
||||
btnCancelUserEdit.addEventListener('click', resetUserForm);
|
||||
|
||||
function resetUserForm() {
|
||||
userFormTitle.textContent = 'Tambah User Baru';
|
||||
manageUserId.value = '';
|
||||
manageUsername.value = '';
|
||||
managePassword.value = '';
|
||||
manageRole.value = 'pengelola';
|
||||
manageIbadahGroup.style.display = 'flex';
|
||||
manageIbadahId.value = '';
|
||||
btnCancelUserEdit.style.display = 'none';
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
function escHtml(str) {
|
||||
if (!str) return '';
|
||||
return String(str).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
}
|
||||
|
||||
// Toast Notification helper
|
||||
function showToast(message, type = 'success') {
|
||||
if (typeof window.showToast === 'function') {
|
||||
window.showToast(message, type);
|
||||
return;
|
||||
}
|
||||
// Fallback alert
|
||||
alert(message);
|
||||
}
|
||||
|
||||
// Run session check on initialization
|
||||
checkSession();
|
||||
})();
|
||||
Reference in New Issue
Block a user