diff --git a/assets/controllers/unique_visitors_per_day_chart_controller.js b/assets/controllers/unique_visitors_per_day_chart_controller.js new file mode 100644 index 0000000..122d995 --- /dev/null +++ b/assets/controllers/unique_visitors_per_day_chart_controller.js @@ -0,0 +1,41 @@ +import { Controller } from "@hotwired/stimulus"; +import Chart from "chart.js/auto"; + +export default class extends Controller { + static values = { + labels: Array, + counts: Array + } + + connect() { + if (!this.hasLabelsValue || !this.hasCountsValue) return; + const ctx = this.element.getContext('2d'); + new Chart(ctx, { + type: 'line', + data: { + labels: this.labelsValue, + datasets: [{ + label: 'Unique Visitors', + data: this.countsValue, + borderColor: 'rgba(255, 99, 132, 1)', + backgroundColor: 'rgba(255, 99, 132, 0.2)', + fill: true, + tension: 0.2, + pointRadius: 2 + }] + }, + options: { + responsive: true, + plugins: { + legend: { display: false }, + title: { display: false } + }, + scales: { + x: { title: { display: true, text: 'Date' } }, + y: { title: { display: true, text: 'Unique Visitors' }, beginAtZero: true, precision: 0 } + } + } + }); + } +} + diff --git a/assets/controllers/visits_per_day_chart_controller.js b/assets/controllers/visits_per_day_chart_controller.js new file mode 100644 index 0000000..ca08e12 --- /dev/null +++ b/assets/controllers/visits_per_day_chart_controller.js @@ -0,0 +1,41 @@ +import { Controller } from "@hotwired/stimulus"; +import Chart from "chart.js/auto"; + +export default class extends Controller { + static values = { + labels: Array, + counts: Array + } + + connect() { + if (!this.hasLabelsValue || !this.hasCountsValue) return; + const ctx = this.element.getContext('2d'); + new Chart(ctx, { + type: 'line', + data: { + labels: this.labelsValue, + datasets: [{ + label: 'Visits', + data: this.countsValue, + borderColor: 'rgba(54, 162, 235, 1)', + backgroundColor: 'rgba(54, 162, 235, 0.2)', + fill: true, + tension: 0.2, + pointRadius: 2 + }] + }, + options: { + responsive: true, + plugins: { + legend: { display: false }, + title: { display: false } + }, + scales: { + x: { title: { display: true, text: 'Date' } }, + y: { title: { display: true, text: 'Visits' }, beginAtZero: true, precision: 0 } + } + } + }); + } +} + diff --git a/composer.lock b/composer.lock index 7151c79..cb797cf 100644 --- a/composer.lock +++ b/composer.lock @@ -13062,6 +13062,6 @@ "ext-openssl": "*", "ext-redis": "*" }, - "platform-dev": {}, + "platform-dev": [], "plugin-api-version": "2.6.0" } diff --git a/importmap.php b/importmap.php index e2b1564..bd37f52 100644 --- a/importmap.php +++ b/importmap.php @@ -96,4 +96,10 @@ return [ 'nostr-tools/nip46' => [ 'version' => '2.17.0', ], + 'chart.js/auto' => [ + 'version' => '4.5.0', + ], + '@kurkle/color' => [ + 'version' => '0.3.4', + ], ]; diff --git a/src/Controller/Administration/VisitorAnalyticsController.php b/src/Controller/Administration/VisitorAnalyticsController.php index 34f5808..37520ab 100644 --- a/src/Controller/Administration/VisitorAnalyticsController.php +++ b/src/Controller/Administration/VisitorAnalyticsController.php @@ -41,6 +41,25 @@ class VisitorAnalyticsController extends AbstractController $mostPopularRoutes = $visitRepository->getMostPopularRoutes(5); $recentVisits = $visitRepository->getRecentVisits(10); + // Calculate unique visitors per day for the last 7 days + $uniqueVisitorsPerDay = []; + for ($i = 6; $i >= 0; $i--) { + $day = (new \DateTimeImmutable("today"))->modify("-{$i} days"); + $start = $day->setTime(0, 0, 0); + $end = $day->setTime(23, 59, 59); + $qb = $visitRepository->createQueryBuilder('v'); + $qb->select('COUNT(DISTINCT v.sessionId)') + ->where('v.visitedAt BETWEEN :start AND :end') + ->andWhere('v.sessionId IS NOT NULL') + ->setParameter('start', $start) + ->setParameter('end', $end); + $count = (int) $qb->getQuery()->getSingleScalarResult(); + $uniqueVisitorsPerDay[] = [ + 'day' => $day->format('Y-m-d'), + 'count' => $count + ]; + } + return $this->render('admin/analytics.html.twig', [ 'visitStats' => $visitStats, 'last24hCount' => $last24hCount, @@ -56,6 +75,7 @@ class VisitorAnalyticsController extends AbstractController 'visitsPerDay' => $visitsPerDay, 'mostPopularRoutes' => $mostPopularRoutes, 'recentVisits' => $recentVisits, + 'uniqueVisitorsPerDay' => $uniqueVisitorsPerDay, ]); } } diff --git a/templates/admin/analytics.html.twig b/templates/admin/analytics.html.twig index b4f09b4..c42c02a 100644 --- a/templates/admin/analytics.html.twig +++ b/templates/admin/analytics.html.twig @@ -35,9 +35,47 @@ +
| Date | +Unique Visitors | +
|---|---|
| {{ stat.day }} | +{{ stat.count }} | +