diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 7855e3e..936fba0 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -19,7 +19,20 @@ class AdminController extends Controller public function index() { $departments = Department::all(); - return view('admin.dashboard', compact('departments')); + + // Collect distinct years from all relevant date fields + $years = collect([ + ActivitiesAttended::selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'), + ActivitiesOrganised::selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'), + BooksPublished::selectRaw('YEAR(date_of_publication) as year')->distinct()->pluck('year'), + ExternalEngagement::selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'), + IvOrganised::selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'), + OnlineCourse::selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'), + Patent::selectRaw('YEAR(date_of_submission) as year')->distinct()->pluck('year'), + Publication::selectRaw('YEAR(end_date) as year')->distinct()->pluck('year'), + ])->flatten()->unique()->sortDesc(); + + return view('admin.dashboard', compact('departments', 'years')); } // View responses submitted by users @@ -186,30 +199,37 @@ class AdminController extends Controller public function analyticsComparison(Request $request) { $departmentId = $request->query('department_id'); + $year = $request->query('year'); $models = [ - 'ActivitiesAttended' => ActivitiesAttended::class, - 'ActivitiesOrganised' => ActivitiesOrganised::class, - 'BooksPublished' => BooksPublished::class, - 'ExternalEngagement' => ExternalEngagement::class, - 'IvOrganised' => IvOrganised::class, - 'OnlineCourse' => OnlineCourse::class, - 'Patent' => Patent::class, - 'Publication' => Publication::class, + 'ActivitiesAttended' => ['class' => ActivitiesAttended::class, 'date_field' => 'end_date'], + 'ActivitiesOrganised' => ['class' => ActivitiesOrganised::class, 'date_field' => 'end_date'], + 'BooksPublished' => ['class' => BooksPublished::class, 'date_field' => 'date_of_publication'], + 'ExternalEngagement' => ['class' => ExternalEngagement::class, 'date_field' => 'end_date'], + 'IvOrganised' => ['class' => IvOrganised::class, 'date_field' => 'end_date'], + 'OnlineCourse' => ['class' => OnlineCourse::class, 'date_field' => 'end_date'], + 'Patent' => ['class' => Patent::class, 'date_field' => 'date_of_submission'], + 'Publication' => ['class' => Publication::class, 'date_field' => 'end_date'], ]; $data = []; - foreach ($models as $label => $model) { - $count = $model::where('department_id', $departmentId)->count(); - $data[] = [ - 'label' => $label, - 'count' => $count, - ]; - $total = array_sum(array_column($data, 'count')); - + foreach ($models as $label => $modelConfig) { + $query = $modelConfig['class']::where('department_id', $departmentId); + if ($year && $year !== 'all') { + $query->whereYear($modelConfig['date_field'], $year); + } + $count = $query->count(); + if ($count > 0) { // Only include data with non-zero count + $data[] = [ + 'label' => $label, + 'count' => $count, + ]; + } } + $total = array_sum(array_column($data, 'count')); + return response()->json([ 'labels' => array_column($data, 'label'), 'values' => array_column($data, 'count'), @@ -220,16 +240,17 @@ class AdminController extends Controller public function analyticsContribution(Request $request) { $model = $request->query('model', 'all'); + $year = $request->query('year'); $models = [ - 'ActivitiesAttended' => ActivitiesAttended::class, - 'ActivitiesOrganised' => ActivitiesOrganised::class, - 'BooksPublished' => BooksPublished::class, - 'ExternalEngagement' => ExternalEngagement::class, - 'IvOrganised' => IvOrganised::class, - 'OnlineCourse' => OnlineCourse::class, - 'Patent' => Patent::class, - 'Publication' => Publication::class, + 'ActivitiesAttended' => ['class' => ActivitiesAttended::class, 'date_field' => 'end_date'], + 'ActivitiesOrganised' => ['class' => ActivitiesOrganised::class, 'date_field' => 'end_date'], + 'BooksPublished' => ['class' => BooksPublished::class, 'date_field' => 'date_of_publication'], + 'ExternalEngagement' => ['class' => ExternalEngagement::class, 'date_field' => 'end_date'], + 'IvOrganised' => ['class' => IvOrganised::class, 'date_field' => 'end_date'], + 'OnlineCourse' => ['class' => OnlineCourse::class, 'date_field' => 'end_date'], + 'Patent' => ['class' => Patent::class, 'date_field' => 'date_of_submission'], + 'Publication' => ['class' => Publication::class, 'date_field' => 'end_date'], ]; $data = []; @@ -239,25 +260,37 @@ class AdminController extends Controller foreach ($departments as $department) { $count = 0; - foreach ($models as $modelClass) { - $count += $modelClass::where('department_id', $department->id)->count(); + foreach ($models as $modelConfig) { + $query = $modelConfig['class']::where('department_id', $department->id); + if ($year && $year !== 'all') { + $query->whereYear($modelConfig['date_field'], $year); + } + $count += $query->count(); + } + if ($count > 0) { // Only include data with non-zero count + $data[] = [ + 'label' => $department->name, + 'count' => $count, + ]; } - $data[] = [ - 'label' => $department->name, - 'count' => $count, - ]; - $total = array_sum(array_column($data, 'count')); } } else { - $modelClass = $models[$model]; - $data = $modelClass::selectRaw('departments.name as label, COUNT(*) as count') + $modelConfig = $models[$model]; + $query = $modelConfig['class']::selectRaw('departments.name as label, COUNT(*) as count') ->join('departments', 'department_id', '=', 'departments.id') - ->groupBy('departments.name') - ->get() - ->toArray(); - $total = array_sum(array_column($data, 'count')); + ->groupBy('departments.name'); + + if ($year && $year !== 'all') { + $query->whereYear($modelConfig['date_field'], $year); + } + + $data = $query->get()->filter(function ($item) { + return $item['count'] > 0; // Filter out data with zero count + })->toArray(); } + $total = array_sum(array_column($data, 'count')); + return response()->json([ 'labels' => array_column($data, 'label'), 'values' => array_column($data, 'count'), diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index b8cd3df..d141aaa 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -17,73 +17,51 @@

Analytics

-
+

Comparison of All Models by Department

- @foreach($departments as $department) @endforeach + +
+ +

Total Contribution by Department

- +
+ + +
-
-

Activities Attended by Department

- -
- - - - - - - - - -
- - -
- -
@endsection @@ -101,9 +79,11 @@ document.addEventListener('DOMContentLoaded', function() { // Comparison Chart Script const departmentSelector = document.getElementById('departmentSelector'); + const comparisonYearSelector = document.getElementById('comparisonYearSelector'); - function fetchComparisonData(departmentId) { - fetch(`{{ route('admin.analytics.comparison', ['department_id' => '']) }}${departmentId}`) + function fetchComparisonData(departmentId, year) { + const yearParam = year === 'all' ? '' : `&year=${year}`; + fetch(`{{ route('admin.analytics.comparison', ['department_id' => '']) }}${departmentId}${yearParam}`) .then(response => response.json()) .then(data => { const ctx = document.getElementById('comparisonChart').getContext('2d'); @@ -111,7 +91,7 @@ window.comparisonChartInstance.destroy(); } window.comparisonChartInstance = new Chart(ctx, { - type: 'pie', + type: 'bar', data: { labels: data.labels, datasets: [{ @@ -123,7 +103,11 @@ 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', - 'rgba(255, 159, 64, 0.2)' + 'rgba(255, 159, 64, 0.2)', + 'rgba(128, 0, 128, 0.2)', // Purple + 'rgba(0, 200, 0, 0.2)', // Green + 'rgba(255, 165, 0, 0.2)', // Orange + 'rgba(0, 0, 255, 0.2)' // Blue ], borderColor: [ 'rgba(255, 99, 132, 1)', @@ -131,7 +115,11 @@ 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', - 'rgba(255, 159, 64, 1)' + 'rgba(255, 159, 64, 1)', + 'rgba(128, 0, 128, 1)', // Purple + 'rgba(0, 128, 0, 1)', // Green + 'rgba(255, 165, 0, 1)', // Orange + 'rgba(0, 0, 255, 1)' // Blue ], borderWidth: 1 }] @@ -141,6 +129,7 @@ plugins: { legend: { position: 'bottom', + display: false }, tooltip: { callbacks: { @@ -150,16 +139,20 @@ } }, datalabels: { - color: '#000', - font: { - weight: 'bold' - }, formatter: (value, ctx) => { return value; } } }, responsive: true, + scales: { + x: { + beginAtZero: true + }, + y: { + beginAtZero: true + } + } } }); // Update or create the total element @@ -174,19 +167,25 @@ }); } - // Initial fetch for department 1 - fetchComparisonData(1); + // Initial fetch for department 1 and all years + fetchComparisonData(1, 'all'); - // Update chart on department change + // Update chart on department or year change departmentSelector.addEventListener('change', function() { - fetchComparisonData(this.value); + fetchComparisonData(this.value, comparisonYearSelector.value); + }); + + comparisonYearSelector.addEventListener('change', function() { + fetchComparisonData(departmentSelector.value, this.value); }); // Contribution Chart Script const modelSelector = document.getElementById('modelSelector'); + const contributionYearSelector = document.getElementById('contributionYearSelector'); - function fetchContributionData(model) { - fetch(`{{ route('admin.analytics.contribution', ['model' => '']) }}${model}`) + function fetchContributionData(model, year) { + const yearParam = year === 'all' ? '' : `&year=${year}`; + fetch(`{{ route('admin.analytics.contribution', ['model' => '']) }}${model}${yearParam}`) .then(response => response.json()) .then(data => { const ctx = document.getElementById('contributionChart').getContext('2d'); @@ -194,12 +193,36 @@ window.contributionChartInstance.destroy(); } window.contributionChartInstance = new Chart(ctx, { - type: 'pie', + type: 'bar', // Changed to bar chart data: { labels: data.labels, datasets: [{ label: 'Total Contribution by Department', data: data.values, + backgroundColor: [ + 'rgba(255, 99, 132, 0.2)', + 'rgba(54, 162, 235, 0.2)', + 'rgba(255, 206, 86, 0.2)', + 'rgba(75, 192, 192, 0.2)', + 'rgba(153, 102, 255, 0.2)', + 'rgba(255, 159, 64, 0.2)', + 'rgba(128, 0, 128, 0.2)', // Purple + 'rgba(0, 200, 0, 0.2)', // Green + 'rgba(255, 165, 0, 0.2)', // Orange + 'rgba(0, 0, 255, 0.2)' // Blue + ], + borderColor: [ + 'rgba(255, 99, 132, 1)', + 'rgba(54, 162, 235, 1)', + 'rgba(255, 206, 86, 1)', + 'rgba(75, 192, 192, 1)', + 'rgba(153, 102, 255, 1)', + 'rgba(255, 159, 64, 1)', + 'rgba(128, 0, 128, 1)', // Purple + 'rgba(0, 128, 0, 1)', // Green + 'rgba(255, 165, 0, 1)', // Orange + 'rgba(0, 0, 255, 1)' // Blue + ], borderWidth: 1 }] }, @@ -208,7 +231,7 @@ plugins: { legend: { position: 'bottom', - display: true + display: false }, tooltip: { callbacks: { @@ -228,6 +251,14 @@ } }, responsive: true, + scales: { + x: { + beginAtZero: true + }, + y: { + beginAtZero: true + } + } } }); // Update or create the total element @@ -242,422 +273,18 @@ }); } - // Initial fetch for all categories - fetchContributionData('all'); + // Initial fetch for all categories and all years + fetchContributionData('all', 'all'); - // Update chart on model change + // Update chart on model or year change modelSelector.addEventListener('change', function() { - fetchContributionData(this.value); + fetchContributionData(this.value, contributionYearSelector.value); }); - // Fetch data for Activities Attended - fetch("{{ route('admin.analytics.activitiesAttended') }}") - .then(response => response.json()) - .then(data => { - const ctx = document.getElementById('activitiesAttendedChart').getContext('2d'); - new Chart(ctx, { - type: 'pie', // Changed to pie chart - data: { - labels: data.labels, - datasets: [{ - label: 'Activities Attended', - data: data.values, - backgroundColor: [ - 'rgba(255, 99, 132, 0.2)', - 'rgba(54, 162, 235, 0.2)', - 'rgba(255, 206, 86, 0.2)', - 'rgba(75, 192, 192, 0.2)' - ], - borderColor: [ - 'rgba(255, 99, 132, 1)', - 'rgba(54, 162, 235, 1)', - 'rgba(255, 206, 86, 1)', - 'rgba(75, 192, 192, 1)' - ], - borderWidth: 1 - }] - }, - plugins: [ChartDataLabels], - options: { - responsive: true, - plugins: { - legend: { - position: 'bottom', - }, - tooltip: { - callbacks: { - label: function(tooltipItem) { - return `${tooltipItem.label}: ${tooltipItem.raw}`; - } - } - }, - datalabels: { - color: '#000', - font: { - weight: 'bold' - }, - formatter: (value, ctx) => { - return value; - } - } - } - } - }); - // Display total for Activities Attended - const activitiesTotal = document.createElement('p'); - activitiesTotal.textContent = `Total: ${data.total}`; - activitiesTotal.classList.add('text-center', 'font-bold', 'mt-2'); - document.getElementById('activitiesAttendedChart').parentElement.appendChild(activitiesTotal); - }); - - // Fetch data for Books Published - fetch("{{ route('admin.analytics.booksPublished') }}") - .then(response => response.json()) - .then(data => { - const ctx = document.getElementById('booksPublishedChart').getContext('2d'); - new Chart(ctx, { - type: 'pie', - data: { - labels: data.labels, - datasets: [{ - label: 'Books Published', - data: data.values, - // backgroundColor: 'rgba(153, 102, 255, 0.2)', - // borderColor: 'rgba(153, 102, 255, 1)', - borderWidth: 1 - }] - }, - plugins: [ChartDataLabels], - options: { - plugins: { - legend: { - position: 'bottom', - }, - tooltip: { - callbacks: { - label: function(tooltipItem) { - return `${tooltipItem.label}: ${tooltipItem.raw}`; - } - } - }, - datalabels: { - color: '#000', - font: { - weight: 'bold' - }, - formatter: (value, ctx) => { - return value; - } - } - }, - responsive: true, - } - }); - const activitiesTotal = document.createElement('p'); - activitiesTotal.textContent = `Total: ${data.total}`; - activitiesTotal.classList.add('text-center', 'font-bold', 'mt-2'); - document.getElementById('booksPublishedChart').parentElement.appendChild(activitiesTotal); - }); - - // Fetch data for Publications - fetch("{{ route('admin.analytics.paperPublished') }}") - .then(response => response.json()) - .then(data => { - const ctx = document.getElementById('publicationsChart').getContext('2d'); - new Chart(ctx, { - type: 'pie', - data: { - labels: data.labels, - datasets: [{ - label: 'Papers Published', - data: data.values, - // backgroundColor: 'rgba(153, 102, 255, 0.2)', - // borderColor: 'rgba(153, 102, 255, 1)', - borderWidth: 1 - }] - }, - plugins: [ChartDataLabels], - options: { - plugins: { - legend: { - position: 'bottom', - }, - tooltip: { - callbacks: { - label: function(tooltipItem) { - return `${tooltipItem.label}: ${tooltipItem.raw}`; - } - } - }, - datalabels: { - color: '#000', - font: { - weight: 'bold' - }, - formatter: (value, ctx) => { - return value; - } - } - }, - responsive: true, - } - }); - const activitiesTotal = document.createElement('p'); - activitiesTotal.textContent = `Total: ${data.total}`; - activitiesTotal.classList.add('text-center', 'font-bold', 'mt-2'); - document.getElementById('publicationsChart').parentElement.appendChild(activitiesTotal); - }); - - fetch("{{ route('admin.analytics.activitiesOrganised') }}") - .then(response => response.json()) - .then(data => { - const ctx = document.getElementById('activitiesOrganisedChart').getContext('2d'); - new Chart(ctx, { - type: 'pie', - data: { - labels: data.labels, - datasets: [{ - label: 'Activities Organised', - data: data.values, - // backgroundColor: 'rgba(153, 102, 255, 0.2)', - // borderColor: 'rgba(153, 102, 255, 1)', - borderWidth: 1 - }] - }, - plugins: [ChartDataLabels], - options: { - plugins: { - legend: { - position: 'bottom', - }, - tooltip: { - callbacks: { - label: function(tooltipItem) { - return `${tooltipItem.label}: ${tooltipItem.raw}`; - } - } - }, - datalabels: { - color: '#000', - font: { - weight: 'bold' - }, - formatter: (value, ctx) => { - return value; - } - } - }, - responsive: true, - } - }); - const activitiesTotal = document.createElement('p'); - activitiesTotal.textContent = `Total: ${data.total}`; - activitiesTotal.classList.add('text-center', 'font-bold', 'mt-2'); - document.getElementById('activitiesOrganisedChart').parentElement.appendChild(activitiesTotal); - }); - - fetch("{{ route('admin.analytics.ivOrganised') }}") - .then(response => response.json()) - .then(data => { - const ctx = document.getElementById('ivOrganisedChart').getContext('2d'); - new Chart(ctx, { - type: 'pie', - data: { - labels: data.labels, - datasets: [{ - label: 'Iv Organised', - data: data.values, - // backgroundColor: 'rgba(153, 102, 255, 0.2)', - // borderColor: 'rgba(153, 102, 255, 1)', - borderWidth: 1 - }] - }, - plugins: [ChartDataLabels], - options: { - plugins: { - legend: { - position: 'bottom', - }, - tooltip: { - callbacks: { - label: function(tooltipItem) { - return `${tooltipItem.label}: ${tooltipItem.raw}`; - } - } - }, - datalabels: { - color: '#000', - font: { - weight: 'bold' - }, - formatter: (value, ctx) => { - return value; - } - } - }, - responsive: true, - } - }); - const activitiesTotal = document.createElement('p'); - activitiesTotal.textContent = `Total: ${data.total}`; - activitiesTotal.classList.add('text-center', 'font-bold', 'mt-2'); - document.getElementById('ivOrganisedChart').parentElement.appendChild(activitiesTotal); - }); - - fetch("{{ route('admin.analytics.externalEngagement') }}") - .then(response => response.json()) - .then(data => { - const ctx = document.getElementById('externalEngagementChart').getContext('2d'); - new Chart(ctx, { - type: 'pie', - data: { - labels: data.labels, - datasets: [{ - label: 'External Engagement', - data: data.values, - // backgroundColor: 'rgba(153, 102, 255, 0.2)', - // borderColor: 'rgba(153, 102, 255, 1)', - borderWidth: 1 - }] - }, - plugins: [ChartDataLabels], - options: { - plugins: { - legend: { - position: 'bottom', - }, - tooltip: { - callbacks: { - label: function(tooltipItem) { - return `${tooltipItem.label}: ${tooltipItem.raw}`; - } - } - }, - datalabels: { - color: '#000', - font: { - weight: 'bold' - }, - formatter: (value, ctx) => { - return value; - } - } - }, - responsive: true, - } - }); - const activitiesTotal = document.createElement('p'); - activitiesTotal.textContent = `Total: ${data.total}`; - activitiesTotal.classList.add('text-center', 'font-bold', 'mt-2'); - document.getElementById('externalEngagementChart').parentElement.appendChild(activitiesTotal); - }); - - fetch("{{ route('admin.analytics.onlineCourse') }}") - .then(response => response.json()) - .then(data => { - const ctx = document.getElementById('onlineCourseChart').getContext('2d'); - new Chart(ctx, { - type: 'pie', - data: { - labels: data.labels, - datasets: [{ - label: 'Online Course', - data: data.values, - // backgroundColor: 'rgba(153, 102, 255, 0.2)', - // borderColor: 'rgba(153, 102, 255, 1)', - borderWidth: 1 - }] - }, - plugins: [ChartDataLabels], - options: { - plugins: { - legend: { - position: 'bottom', - }, - tooltip: { - callbacks: { - label: function(tooltipItem) { - return `${tooltipItem.label}: ${tooltipItem.raw}`; - } - } - }, - datalabels: { - color: '#000', - font: { - weight: 'bold' - }, - formatter: (value, ctx) => { - return value; - } - } - }, - responsive: true, - } - }); - const activitiesTotal = document.createElement('p'); - activitiesTotal.textContent = `Total: ${data.total}`; - activitiesTotal.classList.add('text-center', 'font-bold', 'mt-2'); - document.getElementById('onlineCourseChart').parentElement.appendChild(activitiesTotal); - }); - - fetch("{{ route('admin.analytics.patent') }}") - .then(response => response.json()) - .then(data => { - const ctx = document.getElementById('patentsChart').getContext('2d'); - new Chart(ctx, { - type: 'pie', - data: { - labels: data.labels, - datasets: [{ - label: 'Online Course', - data: data.values, - // backgroundColor: 'rgba(153, 102, 255, 0.2)', - // borderColor: 'rgba(153, 102, 255, 1)', - borderWidth: 1 - }] - }, - plugins: [ChartDataLabels], - options: { - plugins: { - legend: { - position: 'bottom', - }, - tooltip: { - callbacks: { - label: function(tooltipItem) { - return `${tooltipItem.label}: ${tooltipItem.raw}`; - } - } - }, - datalabels: { - color: '#000', - font: { - weight: 'bold' - }, - formatter: (value, ctx) => { - return value; - } - } - }, - responsive: true, - } - }); - const activitiesTotal = document.createElement('p'); - activitiesTotal.textContent = `Total: ${data.total}`; - activitiesTotal.classList.add('text-center', 'font-bold', 'mt-2'); - document.getElementById('patentsChart').parentElement.appendChild(activitiesTotal); - }); - }); - - // Load More Button Script - document.addEventListener('DOMContentLoaded', function() { - const loadMoreButton = document.getElementById('loadMoreGraphs'); - const hiddenGraphs = document.querySelectorAll('#graphs-container .hidden'); - - loadMoreButton.addEventListener('click', function() { - hiddenGraphs.forEach(graph => graph.classList.remove('hidden')); // Show hidden graphs - loadMoreButton.style.display = 'none'; // Hide the button + contributionYearSelector.addEventListener('change', function() { + fetchContributionData(modelSelector.value, this.value); }); }); + @endsection \ No newline at end of file