/home/ejrndhmu/rwberdaya.com/admin/users.php
<?php
require_once '../config/database.php';
require_once '../config/helpers.php';
startSession();
// Check if user is logged in and is admin
if (!isLoggedIn() || !isAdmin()) {
redirect('../login.php');
}
$db = new Database();
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (isset($_POST['add_user'])) {
// Add new user
$username = sanitize($_POST['username']);
$email = sanitize($_POST['email']);
$full_name = sanitize($_POST['full_name']);
$phone = sanitize($_POST['phone']);
$address = sanitize($_POST['address']);
$role = sanitize($_POST['role']);
$password = $_POST['password'];
$errors = [];
// Validation
if (empty($username) || empty($email) || empty($full_name) || empty($password)) {
$errors[] = 'Semua field wajib diisi';
}
if (!validateEmail($email)) {
$errors[] = 'Format email tidak valid';
}
if (strlen($password) < 6) {
$errors[] = 'Password minimal 6 karakter';
}
// Check if username or email already exists
$db->query('SELECT id FROM users WHERE username = :username OR email = :email');
$db->bind(':username', $username);
$db->bind(':email', $email);
if ($db->single()) {
$errors[] = 'Username atau email sudah digunakan';
}
if (empty($errors)) {
$hashed_password = hashPassword($password);
$db->query('INSERT INTO users (username, email, password, full_name, phone, address, role, created_at)
VALUES (:username, :email, :password, :full_name, :phone, :address, :role, NOW())');
$db->bind(':username', $username);
$db->bind(':email', $email);
$db->bind(':password', $hashed_password);
$db->bind(':full_name', $full_name);
$db->bind(':phone', $phone);
$db->bind(':address', $address);
$db->bind(':role', $role);
if ($db->execute()) {
setFlashMessage('success', 'User berhasil ditambahkan');
redirect('users.php');
} else {
$errors[] = 'Gagal menambahkan user';
}
}
} elseif (isset($_POST['edit_user'])) {
// Edit user
$user_id = (int)$_POST['user_id'];
$username = sanitize($_POST['username']);
$email = sanitize($_POST['email']);
$full_name = sanitize($_POST['full_name']);
$phone = sanitize($_POST['phone']);
$address = sanitize($_POST['address']);
$role = sanitize($_POST['role']);
$password = $_POST['password'];
$errors = [];
// Validation
if (empty($username) || empty($email) || empty($full_name)) {
$errors[] = 'Username, email, dan nama lengkap wajib diisi';
}
if (!validateEmail($email)) {
$errors[] = 'Format email tidak valid';
}
// Check if username or email already exists (except current user)
$db->query('SELECT id FROM users WHERE (username = :username OR email = :email) AND id != :user_id');
$db->bind(':username', $username);
$db->bind(':email', $email);
$db->bind(':user_id', $user_id);
if ($db->single()) {
$errors[] = 'Username atau email sudah digunakan';
}
if (empty($errors)) {
if (!empty($password)) {
// Update with new password
if (strlen($password) < 6) {
$errors[] = 'Password minimal 6 karakter';
} else {
$hashed_password = hashPassword($password);
$db->query('UPDATE users SET username = :username, email = :email, password = :password,
full_name = :full_name, phone = :phone, address = :address, role = :role, updated_at = NOW()
WHERE id = :user_id');
$db->bind(':password', $hashed_password);
}
} else {
// Update without changing password
$db->query('UPDATE users SET username = :username, email = :email,
full_name = :full_name, phone = :phone, address = :address, role = :role, updated_at = NOW()
WHERE id = :user_id');
}
if (empty($errors)) {
$db->bind(':username', $username);
$db->bind(':email', $email);
$db->bind(':full_name', $full_name);
$db->bind(':phone', $phone);
$db->bind(':address', $address);
$db->bind(':role', $role);
$db->bind(':user_id', $user_id);
if ($db->execute()) {
setFlashMessage('success', 'User berhasil diupdate');
redirect('users.php');
} else {
$errors[] = 'Gagal mengupdate user';
}
}
}
} elseif (isset($_POST['delete_user'])) {
// Delete user
$user_id = (int)$_POST['user_id'];
// Don't allow deleting current admin
if ($user_id == $_SESSION['user_id']) {
setFlashMessage('error', 'Tidak dapat menghapus akun sendiri');
redirect('users.php');
}
$db->query('DELETE FROM users WHERE id = :user_id');
$db->bind(':user_id', $user_id);
if ($db->execute()) {
setFlashMessage('success', 'User berhasil dihapus');
} else {
setFlashMessage('error', 'Gagal menghapus user');
}
redirect('users.php');
}
}
// Get users with pagination
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$limit = 10;
$offset = ($page - 1) * $limit;
$search = isset($_GET['search']) ? sanitize($_GET['search']) : '';
$role_filter = isset($_GET['role']) ? sanitize($_GET['role']) : '';
// Build query
$where_conditions = [];
$params = [];
if (!empty($search)) {
$where_conditions[] = '(username LIKE :search OR email LIKE :search OR full_name LIKE :search)';
$params[':search'] = '%' . $search . '%';
}
if (!empty($role_filter)) {
$where_conditions[] = 'role = :role';
$params[':role'] = $role_filter;
}
$where_clause = !empty($where_conditions) ? 'WHERE ' . implode(' AND ', $where_conditions) : '';
// Get total count
$db->query('SELECT COUNT(*) as total FROM users ' . $where_clause);
foreach ($params as $key => $value) {
$db->bind($key, $value);
}
$total_users = $db->single()->total;
// Get users
$db->query('SELECT * FROM users ' . $where_clause . ' ORDER BY created_at DESC LIMIT :limit OFFSET :offset');
foreach ($params as $key => $value) {
$db->bind($key, $value);
}
$db->bind(':limit', $limit);
$db->bind(':offset', $offset);
$users = $db->resultSet();
$total_pages = ceil($total_users / $limit);
// Get user for editing if edit_id is provided
$edit_user = null;
if (isset($_GET['edit'])) {
$edit_id = (int)$_GET['edit'];
$db->query('SELECT * FROM users WHERE id = :id');
$db->bind(':id', $edit_id);
$edit_user = $db->single();
}
$flash_message = getFlashMessage();
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kelola User - Admin Toko Pro</title>
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d'
}
}
}
}
}
</script>
</head>
<body class="bg-gray-50">
<div class="flex h-screen">
<?php include 'includes/sidebar.php'; ?>
<!-- Main Content -->
<div class="flex-1 overflow-auto lg:ml-0 ml-0">
<!-- Header -->
<header class="bg-white shadow-sm border-b">
<div class="px-4 lg:px-6 py-4 pt-16 lg:pt-4">
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl font-bold text-gray-800">Kelola User</h1>
<p class="text-gray-600">Manajemen pengguna sistem</p>
</div>
<button onclick="openModal('addUserModal')" class="bg-primary-600 hover:bg-primary-700 text-white px-4 py-2 rounded-lg transition duration-200">
<svg class="w-5 h-5 inline mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
</svg>
Tambah User
</button>
</div>
</div>
</header>
<!-- Content -->
<main class="p-6">
<?php if ($flash_message): ?>
<div class="mb-6 p-4 rounded-lg <?php echo $flash_message['type'] == 'success' ? 'bg-green-50 border border-green-200 text-green-700' : 'bg-red-50 border border-red-200 text-red-700'; ?>">
<?php echo $flash_message['message']; ?>
</div>
<?php endif; ?>
<?php if (isset($errors) && !empty($errors)): ?>
<div class="mb-6 p-4 rounded-lg bg-red-50 border border-red-200 text-red-700">
<ul class="list-disc list-inside">
<?php foreach ($errors as $error): ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<!-- Filters -->
<div class="bg-white rounded-lg shadow-lg p-6 mb-6">
<form method="GET" class="flex flex-col md:flex-row gap-4">
<div class="flex-1">
<input type="text" name="search" value="<?php echo htmlspecialchars($search); ?>"
placeholder="Cari username, email, atau nama..."
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
<div>
<select name="role" class="px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
<option value="">Semua Role</option>
<option value="admin" <?php echo $role_filter == 'admin' ? 'selected' : ''; ?>>Admin</option>
<option value="customer" <?php echo $role_filter == 'customer' ? 'selected' : ''; ?>>Customer</option>
</select>
</div>
<button type="submit" class="bg-primary-600 hover:bg-primary-700 text-white px-6 py-2 rounded-lg transition duration-200">
Cari
</button>
<?php if (!empty($search) || !empty($role_filter)): ?>
<a href="users.php" class="bg-gray-100 hover:bg-gray-200 text-gray-700 px-6 py-2 rounded-lg transition duration-200">
Reset
</a>
<?php endif; ?>
</form>
</div>
<!-- Users Table -->
<div class="bg-white rounded-lg shadow-lg overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">User</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Kontak</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Role</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Terdaftar</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<?php if (empty($users)): ?>
<tr>
<td colspan="5" class="px-6 py-12 text-center text-gray-500">
<svg class="mx-auto h-12 w-12 text-gray-400 mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z"></path>
</svg>
Tidak ada user ditemukan
</td>
</tr>
<?php else: ?>
<?php foreach ($users as $user): ?>
<tr class="hover:bg-gray-50">
<td class="px-6 py-4">
<div class="flex items-center">
<div class="w-10 h-10 bg-primary-600 rounded-full flex items-center justify-center">
<span class="text-white text-sm font-semibold"><?php echo strtoupper(substr($user->full_name, 0, 1)); ?></span>
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900"><?php echo htmlspecialchars($user->full_name); ?></div>
<div class="text-sm text-gray-500">@<?php echo htmlspecialchars($user->username); ?></div>
</div>
</div>
</td>
<td class="px-6 py-4">
<div class="text-sm text-gray-900"><?php echo htmlspecialchars($user->email); ?></div>
<div class="text-sm text-gray-500"><?php echo htmlspecialchars($user->phone ?: '-'); ?></div>
</td>
<td class="px-6 py-4">
<span class="px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full
<?php echo $user->role == 'admin' ? 'bg-purple-100 text-purple-800' : 'bg-green-100 text-green-800'; ?>">
<?php echo ucfirst($user->role); ?>
</span>
</td>
<td class="px-6 py-4 text-sm text-gray-500">
<?php echo formatDate($user->created_at); ?>
</td>
<td class="px-6 py-4 text-sm font-medium">
<div class="flex space-x-2">
<a href="?edit=<?php echo $user->id; ?>"
class="text-primary-600 hover:text-primary-900">
Edit
</a>
<?php if ($user->id != $_SESSION['user_id']): ?>
<button onclick="confirmDelete(<?php echo $user->id; ?>, '<?php echo htmlspecialchars($user->full_name); ?>')"
class="text-red-600 hover:text-red-900">
Hapus
</button>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<?php if ($total_pages > 1): ?>
<div class="bg-white px-4 py-3 border-t border-gray-200 sm:px-6">
<div class="flex items-center justify-between">
<div class="flex-1 flex justify-between sm:hidden">
<?php if ($page > 1): ?>
<a href="?page=<?php echo $page - 1; ?>&search=<?php echo urlencode($search); ?>&role=<?php echo urlencode($role_filter); ?>"
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
Sebelumnya
</a>
<?php endif; ?>
<?php if ($page < $total_pages): ?>
<a href="?page=<?php echo $page + 1; ?>&search=<?php echo urlencode($search); ?>&role=<?php echo urlencode($role_filter); ?>"
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50">
Selanjutnya
</a>
<?php endif; ?>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p class="text-sm text-gray-700">
Menampilkan <span class="font-medium"><?php echo $offset + 1; ?></span> sampai
<span class="font-medium"><?php echo min($offset + $limit, $total_users); ?></span> dari
<span class="font-medium"><?php echo $total_users; ?></span> user
</p>
</div>
<div>
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px">
<?php for ($i = max(1, $page - 2); $i <= min($total_pages, $page + 2); $i++): ?>
<a href="?page=<?php echo $i; ?>&search=<?php echo urlencode($search); ?>&role=<?php echo urlencode($role_filter); ?>"
class="relative inline-flex items-center px-4 py-2 border text-sm font-medium
<?php echo $i == $page ? 'z-10 bg-primary-50 border-primary-500 text-primary-600' : 'bg-white border-gray-300 text-gray-500 hover:bg-gray-50'; ?>">
<?php echo $i; ?>
</a>
<?php endfor; ?>
</nav>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
</main>
</div>
</div>
<!-- Add User Modal -->
<div id="addUserModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden z-50">
<div class="flex items-center justify-center min-h-screen p-4">
<div class="bg-white rounded-lg shadow-xl max-w-md w-full">
<div class="px-6 py-4 border-b">
<h3 class="text-lg font-semibold text-gray-800">Tambah User Baru</h3>
</div>
<form method="POST">
<div class="px-6 py-4 space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Username</label>
<input type="text" name="username" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" name="email" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Nama Lengkap</label>
<input type="text" name="full_name" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Telepon</label>
<input type="text" name="phone"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Alamat</label>
<textarea name="address" rows="3"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"></textarea>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Role</label>
<select name="role" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
<option value="customer">Customer</option>
<option value="admin">Admin</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Password</label>
<input type="password" name="password" required minlength="6"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
</div>
<div class="px-6 py-4 border-t flex justify-end space-x-3">
<button type="button" onclick="closeModal('addUserModal')"
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition duration-200">
Batal
</button>
<button type="submit" name="add_user"
class="px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-lg transition duration-200">
Tambah User
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Edit User Modal -->
<?php if ($edit_user): ?>
<div id="editUserModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 z-50">
<div class="flex items-center justify-center min-h-screen p-4">
<div class="bg-white rounded-lg shadow-xl max-w-md w-full">
<div class="px-6 py-4 border-b">
<h3 class="text-lg font-semibold text-gray-800">Edit User</h3>
</div>
<form method="POST">
<input type="hidden" name="user_id" value="<?php echo $edit_user->id; ?>">
<div class="px-6 py-4 space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Username</label>
<input type="text" name="username" value="<?php echo htmlspecialchars($edit_user->username); ?>" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
<input type="email" name="email" value="<?php echo htmlspecialchars($edit_user->email); ?>" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Nama Lengkap</label>
<input type="text" name="full_name" value="<?php echo htmlspecialchars($edit_user->full_name); ?>" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Telepon</label>
<input type="text" name="phone" value="<?php echo htmlspecialchars($edit_user->phone); ?>"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Alamat</label>
<textarea name="address" rows="3"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500"><?php echo htmlspecialchars($edit_user->address); ?></textarea>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Role</label>
<select name="role" required
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
<option value="customer" <?php echo $edit_user->role == 'customer' ? 'selected' : ''; ?>>Customer</option>
<option value="admin" <?php echo $edit_user->role == 'admin' ? 'selected' : ''; ?>>Admin</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Password Baru (kosongkan jika tidak ingin mengubah)</label>
<input type="password" name="password" minlength="6"
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-primary-500">
</div>
</div>
<div class="px-6 py-4 border-t flex justify-end space-x-3">
<a href="users.php" class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition duration-200">
Batal
</a>
<button type="submit" name="edit_user"
class="px-4 py-2 bg-primary-600 hover:bg-primary-700 text-white rounded-lg transition duration-200">
Update User
</button>
</div>
</form>
</div>
</div>
</div>
<?php endif; ?>
<!-- Delete Confirmation Modal -->
<div id="deleteModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden z-50">
<div class="flex items-center justify-center min-h-screen p-4">
<div class="bg-white rounded-lg shadow-xl max-w-md w-full">
<div class="px-6 py-4">
<h3 class="text-lg font-semibold text-gray-800 mb-2">Konfirmasi Hapus</h3>
<p class="text-gray-600">Apakah Anda yakin ingin menghapus user <span id="deleteUserName" class="font-semibold"></span>?</p>
<p class="text-red-600 text-sm mt-2">Tindakan ini tidak dapat dibatalkan.</p>
</div>
<div class="px-6 py-4 border-t flex justify-end space-x-3">
<button type="button" onclick="closeModal('deleteModal')"
class="px-4 py-2 text-gray-700 bg-gray-100 hover:bg-gray-200 rounded-lg transition duration-200">
Batal
</button>
<form method="POST" class="inline">
<input type="hidden" name="user_id" id="deleteUserId">
<button type="submit" name="delete_user"
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition duration-200">
Hapus
</button>
</form>
</div>
</div>
</div>
</div>
<script>
function openModal(modalId) {
document.getElementById(modalId).classList.remove('hidden');
}
function closeModal(modalId) {
document.getElementById(modalId).classList.add('hidden');
}
function confirmDelete(userId, userName) {
document.getElementById('deleteUserId').value = userId;
document.getElementById('deleteUserName').textContent = userName;
openModal('deleteModal');
}
// Close modal when clicking outside
document.addEventListener('click', function(e) {
if (e.target.classList.contains('bg-opacity-50')) {
e.target.classList.add('hidden');
}
});
</script>
</body>
</html>