Adds visitor dashboard and related features
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
<div class="stats-dashboard">
|
||||
<!-- Time range selector -->
|
||||
<div class="stats-controls">
|
||||
<div class="preset-buttons">
|
||||
@for (preset of presets; track preset.value) {
|
||||
<button
|
||||
class="preset-btn"
|
||||
[class.active]="selectedPreset === preset.value"
|
||||
(click)="selectedPreset = preset.value; onPresetChange()"
|
||||
>
|
||||
{{ preset.label }}
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (selectedPreset === 'custom') {
|
||||
<div class="custom-dates">
|
||||
<label>
|
||||
From
|
||||
<input type="date" [(ngModel)]="customStart" (change)="onPresetChange()" />
|
||||
</label>
|
||||
<label>
|
||||
To
|
||||
<input type="date" [(ngModel)]="customEnd" (change)="onPresetChange()" />
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
|
||||
<button class="btn btn-parse" (click)="triggerParse()" [disabled]="parsing">
|
||||
{{ parsing ? 'Parsing...' : 'Parse New Logs' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (parseProgress) {
|
||||
<div class="parse-progress">{{ parseProgress }}</div>
|
||||
}
|
||||
|
||||
@if (error) {
|
||||
<div class="error-message">{{ error }}</div>
|
||||
}
|
||||
|
||||
@if (loading) {
|
||||
<div class="loading-message">Loading stats...</div>
|
||||
} @else {
|
||||
<!-- Summary card -->
|
||||
<div class="stats-summary">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ summary?.total_unique_visitors ?? 0 }}</div>
|
||||
<div class="stat-label">Unique Visitors</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ geoStats.length }}</div>
|
||||
<div class="stat-label">Countries</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- World Map -->
|
||||
<div class="map-section">
|
||||
<h3>Visitors by Location</h3>
|
||||
<div class="map-container">
|
||||
<div #mapContainer class="map-leaflet"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Visitors Over Time Chart -->
|
||||
<div class="chart-section">
|
||||
<h3>Visitors Over Time</h3>
|
||||
<div class="chart-container">
|
||||
<canvas
|
||||
baseChart
|
||||
[data]="chartData"
|
||||
[options]="chartOptions"
|
||||
[type]="'line'"
|
||||
></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Geo data table -->
|
||||
<div class="geo-table-section">
|
||||
<h3>Visitors by Country</h3>
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Country</th>
|
||||
<th>Code</th>
|
||||
<th>Visitors</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (geo of geoStats; track geo.country_code) {
|
||||
<tr>
|
||||
<td>{{ geo.country }}</td>
|
||||
<td>{{ geo.country_code }}</td>
|
||||
<td>{{ geo.visitors }}</td>
|
||||
</tr>
|
||||
} @empty {
|
||||
<tr><td colspan="3" class="empty-row">No geo data available yet</td></tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
Reference in New Issue
Block a user