Nov 19th,2025 - 2nd Version
This commit is contained in:
parent
c13312a14c
commit
bc846e76cd
219
dashboard.php
219
dashboard.php
@ -29,29 +29,18 @@ foreach ($task_stats as $stat) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$candidate_status_labels = json_encode(array_column($candidate_stats, 'status'));
|
|
||||||
$candidate_status_data = json_encode(array_column($candidate_stats, 'count'));
|
|
||||||
|
|
||||||
$task_status_labels = json_encode(array_column($task_stats, 'status'));
|
|
||||||
$task_status_data = json_encode(array_column($task_stats, 'count'));
|
|
||||||
|
|
||||||
// Candidates per day
|
// Candidates per day
|
||||||
$stmt = $pdo->query("SELECT DATE(created_at) as date, COUNT(*) as count FROM candidates GROUP BY DATE(created_at) ORDER BY DATE(created_at) ASC");
|
$stmt = $pdo->query("SELECT DATE(created_at) as date, COUNT(*) as count FROM candidates GROUP BY DATE(created_at) ORDER BY DATE(created_at) DESC LIMIT 7");
|
||||||
$candidates_per_day = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$candidates_per_day = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
$candidates_per_day_labels = json_encode(array_column($candidates_per_day, 'date'));
|
|
||||||
$candidates_per_day_data = json_encode(array_column($candidates_per_day, 'count'));
|
|
||||||
|
|
||||||
// Tasks per day
|
// Tasks created per day
|
||||||
$stmt = $pdo->query("SELECT DATE(created_at) as date, COUNT(*) as count FROM tasks GROUP BY DATE(created_at) ORDER BY DATE(created_at) ASC");
|
$stmt = $pdo->query("SELECT DATE(created_at) as date, COUNT(*) as count FROM tasks GROUP BY DATE(created_at) ORDER BY DATE(created_at) DESC LIMIT 7");
|
||||||
$tasks_per_day = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$tasks_created_per_day = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
$tasks_per_day_labels = json_encode(array_column($tasks_per_day, 'date'));
|
|
||||||
$tasks_per_day_data = json_encode(array_column($tasks_per_day, 'count'));
|
|
||||||
|
|
||||||
// Tasks completed per day
|
// Tasks completed per day
|
||||||
$stmt = $pdo->query("SELECT DATE(updated_at) as date, COUNT(*) as count FROM tasks WHERE status = 'Done' GROUP BY DATE(updated_at) ORDER BY DATE(updated_at) ASC");
|
$stmt = $pdo->query("SELECT DATE(updated_at) as date, COUNT(*) as count FROM tasks WHERE status = 'Done' GROUP BY DATE(updated_at) ORDER BY DATE(updated_at) DESC LIMIT 7");
|
||||||
$tasks_completed_per_day = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$tasks_completed_per_day = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
$tasks_completed_per_day_labels = json_encode(array_column($tasks_completed_per_day, 'date'));
|
|
||||||
$tasks_completed_per_day_data = json_encode(array_column($tasks_completed_per_day, 'count'));
|
|
||||||
|
|
||||||
// Fetch candidates for table
|
// Fetch candidates for table
|
||||||
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
|
||||||
@ -84,7 +73,6 @@ $total_task_pages = ceil($total_tasks_records / $limit);
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Analytics Dashboard</title>
|
<title>Analytics Dashboard</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
||||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -162,56 +150,67 @@ $total_task_pages = ceil($total_tasks_records / $limit);
|
|||||||
<?php } ?>
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Charts -->
|
<!-- Summaries -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<?php if (hasPermission('view_candidates')) { ?>
|
<?php if (hasPermission('view_candidates')) { ?>
|
||||||
<div class="col-md-4 mb-4">
|
<div class="col-md-6 mb-4">
|
||||||
<div class="card shadow-sm h-100">
|
<div class="card shadow-sm">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Candidates by Status</h5>
|
<h5 class="card-title">Candidates by Status</h5>
|
||||||
<canvas id="candidates-by-status-chart"></canvas>
|
<p class="card-text">
|
||||||
|
<?php foreach ($candidate_stats as $stat): ?>
|
||||||
|
<span class="badge bg-light text-dark me-2"><?php echo htmlspecialchars($stat['status']); ?>: <?php echo $stat['count']; ?></span>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<?php if (hasPermission('view_tasks')) { ?>
|
<?php if (hasPermission('view_tasks')) { ?>
|
||||||
<div class="col-md-4 mb-4">
|
<div class="col-md-6 mb-4">
|
||||||
<div class="card shadow-sm h-100">
|
<div class="card shadow-sm">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Tasks by Status</h5>
|
<h5 class="card-title">Tasks by Status</h5>
|
||||||
<canvas id="tasks-by-status-chart"></canvas>
|
<p class="card-text">
|
||||||
|
<?php foreach ($task_stats as $stat): ?>
|
||||||
|
<span class="badge bg-light text-dark me-2"><?php echo htmlspecialchars($stat['status']); ?>: <?php echo $stat['count']; ?></span>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<?php if (hasPermission('view_candidates')) { ?>
|
<?php if (hasPermission('view_candidates')) { ?>
|
||||||
<div class="col-md-4 mb-4">
|
|
||||||
<div class="card shadow-sm h-100">
|
|
||||||
<div class="card-body">
|
|
||||||
<h5 class="card-title">Candidates per Day</h5>
|
|
||||||
<canvas id="candidates-per-day-chart"></canvas>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<?php } ?>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<?php if (hasPermission('view_tasks')) { ?>
|
|
||||||
<div class="col-md-6 mb-4">
|
<div class="col-md-6 mb-4">
|
||||||
<div class="card shadow-sm h-100">
|
<div class="card shadow-sm">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Tasks Created per Day</h5>
|
<h5 class="card-title">Recent Candidate Activity</h5>
|
||||||
<canvas id="tasks-per-day-chart"></canvas>
|
<p class="card-text">
|
||||||
|
<?php foreach ($candidates_per_day as $day): ?>
|
||||||
|
<span class="badge bg-light text-dark me-2"><?php echo date("M j", strtotime($day['date'])); ?>: <?php echo $day['count']; ?></span>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<?php if (hasPermission('view_tasks')) { ?>
|
<?php if (hasPermission('view_tasks')) { ?>
|
||||||
<div class="col-md-6 mb-4">
|
<div class="col-md-6 mb-4">
|
||||||
<div class="card shadow-sm h-100">
|
<div class="card shadow-sm">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Tasks Completed per Day</h5>
|
<h5 class="card-title">Recent Task Activity</h5>
|
||||||
<canvas id="tasks-completed-per-day-chart"></canvas>
|
<p class="card-text">
|
||||||
|
<strong>Created:</strong>
|
||||||
|
<?php foreach ($tasks_created_per_day as $day): ?>
|
||||||
|
<span class="badge bg-light text-dark me-2"><?php echo date("M j", strtotime($day['date'])); ?>: <?php echo $day['count']; ?></span>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</p>
|
||||||
|
<p class="card-text">
|
||||||
|
<strong>Completed:</strong>
|
||||||
|
<?php foreach ($tasks_completed_per_day as $day): ?>
|
||||||
|
<span class="badge bg-light text-dark me-2"><?php echo date("M j", strtotime($day['date'])); ?>: <?php echo $day['count']; ?></span>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -322,139 +321,5 @@ $total_task_pages = ceil($total_tasks_records / $limit);
|
|||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
// Candidates by Status Chart
|
|
||||||
const candidateCtx = document.getElementById('candidates-by-status-chart').getContext('2d');
|
|
||||||
new Chart(candidateCtx, {
|
|
||||||
type: 'doughnut',
|
|
||||||
data: {
|
|
||||||
labels: <?php echo $candidate_status_labels; ?>,
|
|
||||||
datasets: [{
|
|
||||||
label: 'Candidates',
|
|
||||||
data: <?php echo $candidate_status_data; ?>,
|
|
||||||
backgroundColor: [
|
|
||||||
'rgba(255, 99, 132, 0.7)',
|
|
||||||
'rgba(54, 162, 235, 0.7)',
|
|
||||||
'rgba(255, 206, 86, 0.7)',
|
|
||||||
'rgba(75, 192, 192, 0.7)',
|
|
||||||
'rgba(153, 102, 255, 0.7)',
|
|
||||||
'rgba(255, 159, 64, 0.7)'
|
|
||||||
],
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Tasks by Status Chart
|
|
||||||
const taskCtx = document.getElementById('tasks-by-status-chart').getContext('2d');
|
|
||||||
new Chart(taskCtx, {
|
|
||||||
type: 'bar',
|
|
||||||
data: {
|
|
||||||
labels: <?php echo $task_status_labels; ?>,
|
|
||||||
datasets: [{
|
|
||||||
label: 'Tasks',
|
|
||||||
data: <?php echo $task_status_data; ?>,
|
|
||||||
backgroundColor: [
|
|
||||||
'rgba(255, 99, 132, 0.7)',
|
|
||||||
'rgba(54, 162, 235, 0.7)',
|
|
||||||
'rgba(255, 206, 86, 0.7)',
|
|
||||||
'rgba(75, 192, 192, 0.7)',
|
|
||||||
],
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
beginAtZero: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Candidates per Day Chart
|
|
||||||
const candidatesPerDayCtx = document.getElementById('candidates-per-day-chart').getContext('2d');
|
|
||||||
new Chart(candidatesPerDayCtx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: <?php echo $candidates_per_day_labels; ?>,
|
|
||||||
datasets: [{
|
|
||||||
label: 'Candidates',
|
|
||||||
data: <?php echo $candidates_per_day_data; ?>,
|
|
||||||
backgroundColor: 'rgba(59, 130, 246, 0.2)',
|
|
||||||
borderColor: 'rgba(59, 130, 246, 1)',
|
|
||||||
borderWidth: 2,
|
|
||||||
tension: 0.4
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
beginAtZero: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Tasks per Day Chart
|
|
||||||
const tasksPerDayCtx = document.getElementById('tasks-per-day-chart').getContext('2d');
|
|
||||||
new Chart(tasksPerDayCtx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: <?php echo $tasks_per_day_labels; ?>,
|
|
||||||
datasets: [{
|
|
||||||
label: 'Tasks',
|
|
||||||
data: <?php echo $tasks_per_day_data; ?>,
|
|
||||||
backgroundColor: 'rgba(239, 68, 68, 0.2)',
|
|
||||||
borderColor: 'rgba(239, 68, 68, 1)',
|
|
||||||
borderWidth: 2,
|
|
||||||
tension: 0.4
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
beginAtZero: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Tasks Completed per Day Chart
|
|
||||||
const tasksCompletedPerDayCtx = document.getElementById('tasks-completed-per-day-chart').getContext('2d');
|
|
||||||
new Chart(tasksCompletedPerDayCtx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: <?php echo $tasks_completed_per_day_labels; ?>,
|
|
||||||
datasets: [{
|
|
||||||
label: 'Tasks Completed',
|
|
||||||
data: <?php echo $tasks_completed_per_day_data; ?>,
|
|
||||||
backgroundColor: 'rgba(16, 185, 129, 0.2)',
|
|
||||||
borderColor: 'rgba(16, 185, 129, 1)',
|
|
||||||
borderWidth: 2,
|
|
||||||
tension: 0.4
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
scales: {
|
|
||||||
y: {
|
|
||||||
beginAtZero: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user