Skip to content
Snippets Groups Projects
Verified Commit d5282382 authored by Sofiane Lasri's avatar Sofiane Lasri
Browse files

feat: enhance admin home with visit statistics and charts

- Implemented total visits, visits per day, visits by country, and most visited pages in HomeController.
- Added Vue components for displaying visits per day and visits by country using Chart.js.
- Updated the admin home view to include statistics and integrated Vue components for visual representation.
- Added Chart.js as a dependency in package.json and package-lock.json.
parent 6bc2e00f
No related branches found
No related tags found
1 merge request!57Resolve "Compléter home dashboard admin avec les stats journaliers du site"
Pipeline #1011 passed
......@@ -4,11 +4,32 @@
use App\Http\Controllers\Controller;
use Illuminate\View\View;
use SlProjects\LaravelRequestLogger\app\Models\LoggedRequest;
class HomeController extends Controller
{
public function index(): View
{
return view('admin.home');
$totalVisits = LoggedRequest::count();
$visitsPerDay = LoggedRequest::selectRaw('DATE(created_at) as date, COUNT(*) as count')
->groupBy('date')
->orderBy('date', 'desc')
->take(7)
->get();
$visitsByCountry = LoggedRequest::selectRaw('country_code, COUNT(*) as count')
->whereNotNull('country_code')
->groupBy('country_code')
->orderBy('count', 'desc')
->get();
$mostVisitedPages = LoggedRequest::with('url')
->selectRaw('url_id, COUNT(*) as count')
->groupBy('url_id')
->orderBy('count', 'desc')
->take(5)
->get();
return view('admin.home', compact('totalVisits', 'visitsPerDay', 'visitsByCountry', 'mostVisitedPages'));
}
}
......@@ -9,6 +9,7 @@
"@toast-ui/editor": "^3.2.2",
"@vitejs/plugin-vue": "^5.2.1",
"bootstrap": "^5.3.3",
"chart.js": "^4.4.7",
"color": "^4.2.3",
"glob": "^11.0.0",
"photoswipe": "^5.4.4",
......@@ -488,6 +489,11 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@kurkle/color": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
......@@ -1493,6 +1499,17 @@
"node": ">=8"
}
},
"node_modules/chart.js": {
"version": "4.4.7",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.7.tgz",
"integrity": "sha512-pwkcKfdzTMAU/+jNosKhNL2bHtJc/sSmYgVbuGTEDhzkrhmyihmP7vUc/5ZK9WopidMDHNe3Wm7jOd/WhuHWuw==",
"dependencies": {
"@kurkle/color": "^0.3.0"
},
"engines": {
"pnpm": ">=8"
}
},
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
......
......@@ -20,6 +20,7 @@
"@toast-ui/editor": "^3.2.2",
"@vitejs/plugin-vue": "^5.2.1",
"bootstrap": "^5.3.3",
"chart.js": "^4.4.7",
"color": "^4.2.3",
"glob": "^11.0.0",
"photoswipe": "^5.4.4",
......
<template>
<div>
<canvas id="visits-by-country"></canvas>
</div>
</template>
<script>
import {Chart} from 'chart.js/auto';
export default {
props: ['data'],
mounted() {
const labels = this.data.map(item => item.country_code || 'Inconnu');
const counts = this.data.map(item => item.count);
new Chart(document.getElementById('visits-by-country'), {
type: 'pie',
data: {
labels: labels,
datasets: [
{
label: 'Visites par pays',
data: counts,
backgroundColor: [
'#FF6384',
'#36A2EB',
'#FFCE56',
'#4BC0C0',
'#9966FF',
],
},
],
},
});
},
};
</script>
<template>
<div>
<canvas id="visits-per-day"></canvas>
</div>
</template>
<script>
import {Chart} from 'chart.js/auto';
export default {
props: ['data'],
mounted() {
const labels = this.data.map(item => item.date);
const counts = this.data.map(item => item.count);
new Chart(document.getElementById('visits-per-day'), {
type: 'line',
data: {
labels: labels,
datasets: [
{
label: 'Visites par jour',
data: counts,
borderColor: 'rgba(75, 192, 192, 1)',
backgroundColor: 'rgba(75, 192, 192, 0.2)',
},
],
},
});
},
};
</script>
import {createApp} from "vue";
import VisitsPerDayChart from "../../components/admin/VisitsPerDayChart.vue";
import VisitsByCountryChart from "../../components/admin/VisitsByCountryChart.vue";
const app = createApp();
app.component('visits-per-day-chart', VisitsPerDayChart);
app.component('visits-by-country-chart', VisitsByCountryChart);
app.mount('#admin-home')
\ No newline at end of file
@extends('layouts.admin', ['title' => 'Administration'])
@section('content')
<h1 class="text-2xl font-bold mb-1">Hello world!</h1>
<p>TODO: Faire un bo tablo de stats pour les visites du site :)</p>
<div class="container" id="admin-home">
<h1 class="text-2xl font-bold mb-4">Statistiques des Visites</h1>
<div class="row mb-4">
<div class="col-md-3">
<div class="card">
<div class="card-body text-center">
<h5 class="card-title">Total des Visites</h5>
<p class="card-text text-2xl font-bold">{{ $totalVisits }}</p>
</div>
</div>
</div>
</div>
<div class="row mb-4">
<div class="col-md-6">
<h2 class="text-xl font-bold">Visites par jour</h2>
<div id="visits-per-day-chart">
<visits-per-day-chart :data="{{ json_encode($visitsPerDay) }}"></visits-per-day-chart>
</div>
</div>
<div class="col-md-6">
<h2 class="text-xl font-bold">Visites par pays</h2>
<div id="visits-by-country-chart">
<visits-by-country-chart :data="{{ json_encode($visitsByCountry) }}"></visits-by-country-chart>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2 class="text-xl font-bold">Pages les plus visitées</h2>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>Page</th>
<th>Nombre de visites</th>
</tr>
</thead>
<tbody>
@foreach ($mostVisitedPages as $index => $page)
<tr>
<td>{{ $index + 1 }}</td>
<td>{{ $page->url->url }}</td>
<td>{{ $page->count }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
@vite('resources/js/pages/admin/home.js')
@endsection
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment