clone of github.com/decent-newsroom/newsroom
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

247 lines
11 KiB

{% extends 'layout.html.twig' %}
{% block title %}Visitor Analytics{% endblock %}
{% block body %}
<div class="analytics-container">
<h1>Page Visit Analytics</h1>
<div class="analytics-summary-row">
<div class="analytics-card">
<h2>Article Publish Activity</h2>
<ul class="analytics-stats">
<li><strong>Last hour:</strong> {{ articlePublishStats.last_hour|number_format }}</li>
<li><strong>Last 24 hours:</strong> {{ articlePublishStats.last_24_hours|number_format }}</li>
<li><strong>Last 7 days:</strong> {{ articlePublishStats.last_7_days|number_format }}</li>
<li><strong>Last 30 days:</strong> {{ articlePublishStats.last_30_days|number_format }}</li>
<li><strong>All time:</strong> {{ articlePublishStats.all_time|number_format }}</li>
</ul>
<p class="analytics-note">Number of times articles were published via the API endpoint</p>
</div>
</div>
<div class="analytics-summary-row">
<div class="analytics-card">
<h2>Total Visits</h2>
<ul class="analytics-stats">
<li><strong>Last 24 hours:</strong> {{ visitsLast24Hours }}</li>
<li><strong>Last 7 days:</strong> {{ visitsLast7Days }}</li>
<li><strong>All time:</strong> {{ totalVisits }}</li>
</ul>
</div>
<div class="analytics-card">
<h2>Unique Visitors</h2>
<ul class="analytics-stats">
<li><strong>Last 24 hours:</strong> {{ uniqueVisitorsLast24Hours }}</li>
<li><strong>Last 7 days:</strong> {{ uniqueVisitorsLast7Days }}</li>
<li><strong>All time:</strong> {{ totalUniqueVisitors }}</li>
</ul>
<p class="analytics-note">Tracked by session ID (includes both anonymous and logged-in visitors)</p>
</div>
<div class="analytics-card">
<h2>Unique Visitors Per Day (Last 7 Days)</h2>
<canvas id="uniqueVisitorsPerDayChart"
data-controller="unique-visitors-per-day-chart"
data-unique-visitors-per-day-chart-labels-value='{{ dailyUniqueVisitorCountsLast7Days|map(stat => stat.day)|json_encode()|e('html_attr') }}'
data-unique-visitors-per-day-chart-counts-value='{{ dailyUniqueVisitorCountsLast7Days|map(stat => stat.count)|json_encode()|e('html_attr') }}'
height="80"></canvas>
<noscript>
<p><em>Enable JavaScript to see the unique visitors per day chart.</em></p>
</noscript>
<div style="margin-top:1em"></div>
<table class="analytics-table">
<thead>
<tr>
<th>Date</th>
<th class="text-right">Unique Visitors</th>
</tr>
</thead>
<tbody>
{% for stat in dailyUniqueVisitorCountsLast7Days %}
<tr>
<td>{{ stat.day }}</td>
<td class="text-right">{{ stat.count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="analytics-card">
<h2>Engagement</h2>
<ul class="analytics-stats">
<li><strong>Avg. Visits/Session:</strong> {{ averageVisitsPerSession }}</li>
<li><strong>Bounce Rate:</strong> {{ bounceRate }}%</li>
</ul>
</div>
</div>
<div class="analytics-card">
<h2>Top 5 Visited Articles (Last 24 Hours)</h2>
{% if topArticlesLast24Hours|length > 0 %}
<table class="analytics-table">
<thead>
<tr>
<th>Article Path</th>
<th class="text-right">Visits</th>
</tr>
</thead>
<tbody>
{% for stat in topArticlesLast24Hours %}
<tr>
<td><a href="{{ stat.route }}" target="_blank">{{ stat.route }}</a></td>
<td class="text-right">{{ stat.count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No article visits recorded in the last 24 hours.</p>
{% endif %}
</div>
<div class="analytics-card">
<h2>Visits Per Day (Last 30 Days)</h2>
{% if dailyVisitCountsLast30Days|length > 0 %}
<canvas id="visitsPerDayChart"
data-controller="analytics--visits-per-day-chart"
data-analytics--visits-per-day-chart-labels-value='{{ dailyVisitCountsLast30Days|map(stat => stat.day|date('Y-m-d'))|json_encode()|e('html_attr') }}'
data-analytics--visits-per-day-chart-counts-value='{{ dailyVisitCountsLast30Days|map(stat => stat.count)|json_encode()|e('html_attr') }}'
height="80"></canvas>
<noscript>
<p><em>Enable JavaScript to see the visits per day chart.</em></p>
</noscript>
<div style="margin-top:1em"></div>
<table class="analytics-table">
<thead>
<tr>
<th>Date</th>
<th class="text-right">Visits</th>
</tr>
</thead>
<tbody>
{% for stat in dailyVisitCountsLast30Days %}
<tr>
<td>{{ stat.day|date('Y-m-d') }}</td>
<td class="text-right">{{ stat.count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No visit data for the last 30 days.</p>
{% endif %}
</div>
<div class="analytics-card">
<h2>Most Popular Routes (All Time)</h2>
{% if topRoutesAllTime|length > 0 %}
<table class="analytics-table">
<thead>
<tr>
<th>Route</th>
<th class="text-right">Visits</th>
</tr>
</thead>
<tbody>
{% for stat in topRoutesAllTime %}
<tr>
<td>{{ stat.route }}</td>
<td class="text-right">{{ stat.count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No route data available.</p>
{% endif %}
</div>
<div class="analytics-card">
<h2>Recent Visits</h2>
{% if recentVisitRecords|length > 0 %}
<table class="analytics-table">
<thead>
<tr>
<th>Route</th>
<th>Session ID</th>
<th>Visited At</th>
</tr>
</thead>
<tbody>
{% for visit in recentVisitRecords %}
<tr>
<td>{{ visit.route }}</td>
<td><code>{{ visit.sessionId|slice(0, 12) }}...</code></td>
<td>{{ visit.visitedAt|date('Y-m-d H:i') }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No recent visits recorded.</p>
{% endif %}
</div>
<div class="analytics-card">
<h2>Visit Count by Route (Last 7 Days)</h2>
{% set filteredRouteVisitCounts = routeVisitCountsLast7Days|filter(stat => stat.count >= 5) %}
{% if filteredRouteVisitCounts|length > 0 %}
<table class="analytics-table">
<thead>
<tr>
<th>Route</th>
<th class="text-right">#</th>
</tr>
</thead>
<tbody>
{% for stat in filteredRouteVisitCounts %}
<tr>
<td>{{ stat.route }}</td>
<td class="text-right">{{ stat.count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No routes with 5 or more visits recorded in the last 7 days.</p>
{% endif %}
</div>
<div class="analytics-card">
<h2>Visitor Sessions (Last 7 Days)</h2>
{% if visitsBySessionLast7Days|length > 0 %}
<table class="analytics-table">
<thead>
<tr>
<th>Session ID</th>
<th class="text-right">Visits</th>
<th class="text-right">First Visit</th>
<th class="text-right">Last Visit</th>
</tr>
</thead>
<tbody>
{% for stat in visitsBySessionLast7Days %}
{% if stat.visitCount > 1 %}
<tr>
<td><code>{{ stat.sessionId|slice(0, 12) }}...</code></td>
<td class="text-right">{{ stat.visitCount }}</td>
<td class="text-right">{{ stat.firstVisit|date('M d, H:i') }}</td>
<td class="text-right">{{ stat.lastVisit|date('M d, H:i') }}</td>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
{% else %}
<p>No visitor sessions recorded in the last 7 days.</p>
{% endif %}
</div>
<div class="analytics-info">
<p>Visit tracking is automated via event listener. Session IDs track all unique visitors (both anonymous and logged-in) for accurate engagement analytics.</p>
</div>
</div>
{% endblock %}