34784-vm/dashboard.php
Flatlogic Bot 0e7f6ab776 Edutask V1
2025-10-08 08:54:03 +00:00

533 lines
26 KiB
PHP

<?php
session_start();
require_once __DIR__ . '/db/config.php';
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
header('Location: index.php');
exit;
}
$user_id = $_SESSION['user_id'];
$username = $_SESSION['username'];
$role = $_SESSION['role'];
$page_title = ucfirst($role) . ' Dashboard';
$dashboard_content = '';
$students = []; // Initialize students array
try {
$pdo = db();
switch ($role) {
case 'siswa':
$stmt = $pdo->prepare(
"SELECT t.id, t.title, t.description, t.due_date, ta.status, ta.id as assignment_id
FROM tasks t
JOIN task_assignments ta ON t.id = ta.task_id
WHERE ta.assigned_to_user_id = ?
ORDER BY t.due_date ASC"
);
$stmt->execute([$user_id]);
$tasks = $stmt->fetchAll();
$dashboard_content = '<h2>Daftar Tugas Anda</h2>';
if (empty($tasks)) {
$dashboard_content .= '<p>Belum ada tugas untuk Anda. Selamat beristirahat!</p>';
} else {
$dashboard_content .= '<div class="task-list">';
foreach ($tasks as $task) {
$status_class = 'status-' . str_replace('_', '-', $task['status']);
$due_date = $task['due_date'] ? date('d M Y', strtotime($task['due_date'])) : 'Tidak ada tenggat';
$is_done = $task['status'] === 'done';
$dashboard_content .= '
<div class="task-item ' . ($is_done ? 'done' : '') . '" id="task-' . htmlspecialchars($task['assignment_id']) . '">
<div class="task-info">
<h3>' . htmlspecialchars($task['title']) . '</h3>
<p>' . htmlspecialchars($task['description']) . '</p>
<small class="due-date">Tenggat: ' . $due_date . '</small>
</div>
<div class="task-actions">
<span class="status-badge ' . $status_class . '">' . ucfirst(str_replace('_', ' ', $task['status'])) . '</span>
<button class="complete-btn" data-assignment-id="' . htmlspecialchars($task['assignment_id']) . '" ' . ($is_done ? 'disabled' : '') . '>
' . ($is_done ? 'Selesai' : 'Tandai Selesai') . '
</button>
</div>
</div>';
}
$dashboard_content .= '</div>';
}
break;
case 'guru':
// Fetch tasks created by this teacher
$stmt_tasks = $pdo->prepare("SELECT * FROM tasks WHERE created_by_user_id = ? ORDER BY created_at DESC");
$stmt_tasks->execute([$user_id]);
$created_tasks = $stmt_tasks->fetchAll();
// Fetch all students for the assignment form
$stmt_students = $pdo->prepare("SELECT id, username FROM users WHERE role = 'siswa' ORDER BY username ASC");
$stmt_students->execute();
$students = $stmt_students->fetchAll();
$dashboard_content = '
<div class="teacher-header">
<h2>Manajemen Tugas</h2>
<button id="create-task-btn" class="btn btn-primary">Buat Tugas Baru</button>
</div>
<div class="task-management-table">
<h3>Daftar Tugas yang Dibuat</h3>
<table id="task-table">
<thead>
<tr>
<th>Judul</th>
<th>Tenggat Waktu</th>
<th>Dibuat pada</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>';
if (empty($created_tasks)) {
$dashboard_content .= '<tr id="no-tasks-row"><td colspan="4">Anda belum membuat tugas apapun.</td></tr>';
} else {
foreach ($created_tasks as $task) {
$dashboard_content .= '
<tr data-task-id="' . $task['id'] . '">
<td>' . htmlspecialchars($task['title']) . '</td>
<td>' . ($task['due_date'] ? date('d M Y', strtotime($task['due_date'])) : '-') . '</td>
<td>' . date('d M Y', strtotime($task['created_at'])) . '</td>
<td class="actions">
<button class="btn btn-secondary btn-sm">Edit</button>
<button class="btn btn-danger btn-sm">Hapus</button>
</td>
</tr>';
}
}
$dashboard_content .= '
</tbody>
</table>
</div>
';
break;
case 'admin':
// Fetch all users for the admin view
$stmt = $pdo->prepare("SELECT id, username, role, created_at FROM users ORDER BY created_at DESC");
$stmt->execute();
$users = $stmt->fetchAll();
$dashboard_content = '
<div class="d-flex justify-content-between align-items-center mb-4">
<h2 class="h3">Manajemen Pengguna</h2>
<button class="btn btn-primary" id="create-user-btn">
<i class="fas fa-plus me-2"></i>Buat Pengguna Baru
</button>
</div>
<div class="card">
<div class="card-body p-0">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Peran</th>
<th>Bergabung pada</th>
<th>Aksi</th>
</tr>
</thead>
<tbody id="user-list-tbody">';
if (empty($users)) {
$dashboard_content .= '<tr><td colspan="5" class="text-center">Tidak ada pengguna yang ditemukan.</td></tr>';
} else {
foreach ($users as $user) {
$dashboard_content .= '
<tr data-user-id="' . $user['id'] . '">
<td>' . htmlspecialchars($user['id']) . '</td>
<td>' . htmlspecialchars($user['username']) . '</td>
<td><span class="badge bg-secondary">' . htmlspecialchars($user['role']) . '</span></td>
<td>' . date('d M Y', strtotime($user['created_at'])) . '</td>
<td>
<button class="btn btn-sm btn-outline-primary edit-user-btn">Edit</button>
<button class="btn btn-sm btn-outline-danger delete-user-btn">Hapus</button>
</td>
</tr>';
}
}
$dashboard_content .= '
</tbody>
</table>
</div>
</div>
';
break;
default:
$dashboard_content = '<h2>Selamat Datang!</h2><p>Dashboard Anda sudah siap.</p>';
break;
}
} catch (PDOException $e) {
$dashboard_content = '<p>Gagal memuat data. Silakan coba lagi nanti.</p>';
}
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($page_title); ?> - EduTask</title>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&family=Open+Sans:wght@400;600&display=swap" rel="stylesheet">
<style>
:root {
--primary-color: #4A90E2;
--secondary-color: #50E3C2;
--danger-color: #e74c3c;
--background-color: #F9FAFB;
--surface-color: #FFFFFF;
--text-color: #333333;
--light-gray: #EAEAEA;
--success-color: #28a745;
--warning-color: #ffc107;
--todo-color: #6c757d;
}
body { font-family: 'Open Sans', sans-serif; background-color: var(--background-color); color: var(--text-color); margin: 0; padding: 0; display: flex; flex-direction: column; min-height: 100vh; }
.navbar { background-color: var(--surface-color); padding: 1rem 2rem; box-shadow: 0 2px 4px rgba(0,0,0,0.05); display: flex; justify-content: space-between; align-items: center; }
.navbar-brand { font-family: 'Poppins', sans-serif; font-size: 1.5rem; font-weight: 700; color: var(--primary-color); text-decoration: none; }
.navbar-menu { display: flex; align-items: center; }
.user-info { margin-right: 1.5rem; font-weight: 600; text-align: right; }
.user-info .role { font-weight: 400; font-size: 0.8rem; color: #777; display: block; }
.logout-btn { font-family: 'Poppins', sans-serif; background-color: var(--primary-color); color: white; border: none; padding: 0.6rem 1.2rem; border-radius: 5px; cursor: pointer; text-decoration: none; font-size: 0.9rem; font-weight: 600; transition: background-color 0.3s ease; }
.logout-btn:hover { background: linear-gradient(to right, var(--primary-color), var(--secondary-color)); }
.main-content { flex: 1; padding: 2rem; }
.dashboard-card { background-color: var(--surface-color); border-radius: 8px; padding: 2rem; box-shadow: 0 4px 12px rgba(0,0,0,0.08); }
.dashboard-card h2 { font-family: 'Poppins', sans-serif; color: var(--primary-color); margin-top: 0; }
footer { text-align: center; padding: 1rem; background-color: var(--surface-color); font-size: 0.9rem; color: #888; }
/* General Button Styles */
.btn { font-family: 'Poppins', sans-serif; border: none; padding: 0.6rem 1.2rem; border-radius: 5px; cursor: pointer; font-weight: 600; transition: background-color 0.3s ease, box-shadow 0.3s ease; }
.btn-primary { background-color: var(--primary-color); color: white; }
.btn-primary:hover { background-color: #3a80d2; }
.btn-secondary { background-color: #bdc3c7; color: #fff; }
.btn-danger { background-color: var(--danger-color); color: white; }
.btn-sm { padding: 0.4rem 0.8rem; font-size: 0.85rem; }
/* Siswa: Task List Styles */
.task-list { display: flex; flex-direction: column; gap: 1rem; }
.task-item { background-color: #fff; border: 1px solid var(--light-gray); border-radius: 8px; padding: 1rem 1.5rem; display: flex; justify-content: space-between; align-items: center; transition: box-shadow 0.3s ease, border-color 0.3s ease; }
.task-item:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.07); }
.task-item.done { background-color: #f1fef4; border-left: 5px solid var(--success-color); }
.task-item.done h3 { text-decoration: line-through; color: #888; }
.task-info h3 { margin: 0 0 0.25rem 0; font-family: 'Poppins', sans-serif; }
.task-info p { margin: 0 0 0.5rem 0; font-size: 0.95rem; color: #555; }
.task-info .due-date { font-size: 0.8rem; color: #888; }
.task-actions { display: flex; align-items: center; gap: 1rem; }
.status-badge { padding: 0.25rem 0.6rem; border-radius: 12px; font-size: 0.8rem; font-weight: 600; color: white; }
.status-todo { background-color: var(--todo-color); }
.status-in-progress { background-color: var(--warning-color); }
.status-done { background-color: var(--success-color); }
.complete-btn { background-color: var(--success-color); color: white; border: none; padding: 0.5rem 1rem; border-radius: 5px; cursor: pointer; font-weight: 600; transition: background-color 0.3s ease; }
.complete-btn:disabled { background-color: #a9d6b4; cursor: not-allowed; }
/* Guru: Task Management Styles */
.teacher-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; }
.task-management-table table { width: 100%; border-collapse: collapse; }
.task-management-table th, .task-management-table td { padding: 0.8rem 1rem; text-align: left; border-bottom: 1px solid var(--light-gray); }
.task-management-table th { font-family: 'Poppins', sans-serif; background-color: #f8f9fa; }
.task-management-table .actions { display: flex; gap: 0.5rem; }
/* Modal Styles */
.modal-backdrop { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); z-index: 100; display: none; justify-content: center; align-items: center; }
.modal-content { background-color: var(--surface-color); border-radius: 8px; padding: 2rem; width: 90%; max-width: 600px; box-shadow: 0 5px 15px rgba(0,0,0,0.3); position: relative; }
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1.5rem; }
.modal-header h3 { margin: 0; font-family: 'Poppins', sans-serif; }
.close-btn { font-size: 1.5rem; font-weight: bold; color: #aaa; cursor: pointer; border: none; background: none; }
.form-group { margin-bottom: 1rem; }
.form-group label { display: block; margin-bottom: 0.5rem; font-weight: 600; }
.form-group input, .form-group textarea { width: 100%; padding: 0.75rem; border: 1px solid var(--light-gray); border-radius: 5px; font-size: 1rem; }
.student-list { max-height: 150px; overflow-y: auto; border: 1px solid var(--light-gray); padding: 0.5rem; border-radius: 5px; }
.student-list label { display: block; padding: 0.5rem; }
.student-list label:hover { background-color: #f8f9fa; }
.form-actions { text-align: right; margin-top: 1.5rem; }
</style>
</head>
<body>
<nav class="navbar">
<a href="dashboard.php" class="navbar-brand">EduTask</a>
<div class="navbar-menu">
<div class="user-info">
Halo, <?php echo htmlspecialchars($username); ?>!
<span class="role">(<?php echo htmlspecialchars($role); ?>)</span>
</div>
<a href="auth.php?action=logout" class="logout-btn">Logout</a>
</div>
</nav>
<main class="main-content">
<div class="dashboard-card">
<?php echo $dashboard_content; ?>
</div>
</main>
<?php if ($role === 'guru'): ?>
<div id="create-task-modal" class="modal-backdrop">
<div class="modal-content">
<div class="modal-header">
<h3>Buat Tugas Baru</h3>
<button class="close-btn">&times;</button>
</div>
<form id="create-task-form">
<div class="form-group">
<label for="task-title">Judul Tugas</label>
<input type="text" id="task-title" name="title" required>
</div>
<div class="form-group">
<label for="task-description">Deskripsi</label>
<textarea id="task-description" name="description" rows="3"></textarea>
</div>
<div class="form-group">
<label for="task-due-date">Tenggat Waktu</label>
<input type="date" id="task-due-date" name="due_date">
</div>
<div class="form-group">
<label>Tugaskan kepada Siswa</label>
<div class="student-list">
<?php if (empty($students)): ?>
<p>Tidak ada siswa yang ditemukan.</p>
<?php else: ?>
<label><input type="checkbox" id="select-all-students"> Pilih Semua</label>
<?php foreach ($students as $student): ?>
<label>
<input type="checkbox" name="student_ids[]" value="<?php echo $student['id']; ?>">
<?php echo htmlspecialchars($student['username']); ?>
</label>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Simpan Tugas</button>
</div>
</form>
</div>
</div>
<?php endif; ?>
<?php if ($role === 'admin'): ?>
<div id="user-modal" class="modal-backdrop">
<div class="modal-content">
<div class="modal-header">
<h3 id="user-modal-title">Buat Pengguna Baru</h3>
<button class="close-btn">&times;</button>
</div>
<form id="user-form">
<input type="hidden" id="user-id" name="user_id">
<div class="form-group">
<label for="user-username">Username</label>
<input type="text" id="user-username" name="username" required>
</div>
<div class="form-group">
<label for="user-password">Password</label>
<input type="password" id="user-password" name="password">
<small>Kosongkan jika tidak ingin mengubah password.</small>
</div>
<div class="form-group">
<label for="user-role">Peran</label>
<select id="user-role" name="role" required>
<option value="siswa">Siswa</option>
<option value="guru">Guru</option>
<option value="admin">Admin</option>
</select>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Simpan</button>
</div>
</form>
</div>
</div>
<?php endif; ?>
<footer>
<p>&copy; <?php echo date('Y'); ?> EduTask. Hak cipta dilindungi.</p>
</footer>
<script>
document.addEventListener('DOMContentLoaded', function() {
const role = '<?php echo $role; ?>';
// --- Generic API call function ---
function callApi(body) {
return fetch('api.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(body),
}).then(response => response.json());
}
// --- Logic for Siswa ---
if (role === 'siswa') {
const taskList = document.querySelector('.task-list');
if (taskList) {
taskList.addEventListener('click', function(e) {
if (e.target && e.target.classList.contains('complete-btn')) {
const button = e.target;
const assignmentId = button.getAttribute('data-assignment-id');
if (button.disabled) return;
callApi({ action: 'update_task_status', assignment_id: assignmentId, status: 'done' })
.then(data => {
if (data.success) {
const taskItem = document.getElementById('task-' + assignmentId);
taskItem.classList.add('done');
button.textContent = 'Selesai';
button.disabled = true;
const statusBadge = taskItem.querySelector('.status-badge');
statusBadge.textContent = 'Done';
statusBadge.classList.remove('status-todo', 'status-in-progress');
statusBadge.classList.add('status-done');
} else {
alert('Gagal memperbarui status tugas: ' + (data.error || 'Unknown error'));
}
}).catch(error => console.error('Error:', error));
}
});
}
}
// --- Logic for Guru ---
if (role === 'guru') {
const modal = document.getElementById('create-task-modal');
const createTaskBtn = document.getElementById('create-task-btn');
const closeBtn = modal ? modal.querySelector('.close-btn') : null;
const form = document.getElementById('create-task-form');
const selectAllCheckbox = document.getElementById('select-all-students');
if (createTaskBtn) createTaskBtn.addEventListener('click', () => { modal.style.display = 'flex'; });
if (closeBtn) closeBtn.addEventListener('click', () => { modal.style.display = 'none'; });
window.addEventListener('click', (e) => { if (e.target === modal) modal.style.display = 'none'; });
if (selectAllCheckbox) {
selectAllCheckbox.addEventListener('change', function() {
form.querySelectorAll('input[name="student_ids[]"]').forEach(cb => { cb.checked = this.checked; });
});
}
if (form) {
form.addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(form);
const student_ids = formData.getAll('student_ids[]');
if (student_ids.length === 0) {
alert('Pilih minimal satu siswa untuk ditugaskan.');
return;
}
callApi({
action: 'create_task',
title: formData.get('title'),
description: formData.get('description'),
due_date: formData.get('due_date'),
student_ids: student_ids
}).then(data => {
if (data.success) {
alert('Tugas berhasil dibuat!');
modal.style.display = 'none';
form.reset();
location.reload(); // Simple reload to show the new task
} else {
alert('Gagal membuat tugas: ' + (data.error || 'Unknown error'));
}
}).catch(error => console.error('Error:', error));
});
}
}
// --- Logic for Admin ---
if (role === 'admin') {
const userModal = document.getElementById('user-modal');
const createUserBtn = document.getElementById('create-user-btn');
const userCloseBtn = userModal ? userModal.querySelector('.close-btn') : null;
const userForm = document.getElementById('user-form');
const userListTbody = document.getElementById('user-list-tbody');
const openUserModal = (user = null) => {
userForm.reset();
const modalTitle = document.getElementById('user-modal-title');
const userIdInput = document.getElementById('user-id');
const passwordInput = document.getElementById('user-password');
if (user) {
modalTitle.textContent = 'Edit Pengguna';
userIdInput.value = user.id;
document.getElementById('user-username').value = user.username;
document.getElementById('user-role').value = user.role;
passwordInput.required = false;
} else {
modalTitle.textContent = 'Buat Pengguna Baru';
userIdInput.value = '';
passwordInput.required = true;
}
userModal.style.display = 'flex';
};
const closeUserModal = () => {
userModal.style.display = 'none';
};
if (createUserBtn) createUserBtn.addEventListener('click', () => openUserModal());
if (userCloseBtn) userCloseBtn.addEventListener('click', closeUserModal);
window.addEventListener('click', (e) => { if (e.target === userModal) closeUserModal(); });
userListTbody.addEventListener('click', e => {
const target = e.target;
const userRow = target.closest('tr');
const userId = userRow.dataset.userId;
if (target.classList.contains('edit-user-btn')) {
const username = userRow.cells[1].textContent;
const role = userRow.cells[2].textContent;
openUserModal({ id: userId, username, role });
}
if (target.classList.contains('delete-user-btn')) {
if (confirm(`Apakah Anda yakin ingin menghapus pengguna dengan ID ${userId}?`)) {
callApi({ action: 'delete_user', user_id: userId }).then(data => {
if (data.success) {
alert('Pengguna berhasil dihapus.');
location.reload();
} else {
alert('Gagal menghapus pengguna: ' + (data.error || 'Unknown error'));
}
}).catch(error => console.error('Error:', error));
}
}
});
userForm.addEventListener('submit', e => {
e.preventDefault();
const formData = new FormData(userForm);
const userId = formData.get('user_id');
const action = userId ? 'update_user' : 'create_user';
let body = { action };
for (let [key, value] of formData.entries()) {
body[key] = value;
}
callApi(body).then(data => {
if (data.success) {
alert(`Pengguna berhasil ${userId ? 'diperbarui' : 'dibuat'}.`);
closeUserModal();
location.reload();
} else {
alert('Gagal: ' + (data.error || 'Unknown error'));
}
}).catch(error => console.error('Error:', error));
});
}
});
</script>
</body>
</html>