Enhances employee statistics page with rich dashboard

Refactors employee statistics view with comprehensive charts and tables
Adds detailed revenue, utilization, and booking tracking components
Introduces dynamic data loading and chart visualization for employee performance
This commit is contained in:
Janus C. H. Knudsen 2026-01-22 23:28:33 +01:00
parent b921e26e48
commit eaae745c42
8 changed files with 543 additions and 70 deletions

View file

@ -1,35 +1,75 @@
@model PlanTempus.Application.Features.Employees.Components.EmployeeDetailStatsViewModel
<swp-detail-grid>
<swp-card>
<swp-detail-grid class="stats-layout">
<!-- Stats Row (4 cards) -->
<swp-stats-row class="cols-4 full-width">
<swp-stat-card class="highlight">
<swp-stat-value id="statBookingsMonth">42</swp-stat-value>
<swp-stat-label>Bookinger denne måned</swp-stat-label>
</swp-stat-card>
<swp-stat-card>
<swp-stat-value id="statBookedValue">30.825 kr</swp-stat-value>
<swp-stat-label>Værdi af bookede services</swp-stat-label>
<swp-stat-subtitle id="statBookedSubtitle">Baseret på 49 bookinger</swp-stat-subtitle>
</swp-stat-card>
<swp-stat-card>
<swp-stat-value id="statRevenueMonth">28.450 kr</swp-stat-value>
<swp-stat-label>Omsætning denne måned</swp-stat-label>
</swp-stat-card>
<swp-stat-card>
<swp-stat-value id="statReturnCustomers">68%</swp-stat-value>
<swp-stat-label>Gengangere</swp-stat-label>
</swp-stat-card>
</swp-stats-row>
<!-- Revenue & Utilization Chart (dual-axis: bars + line) -->
<swp-card class="full-width">
<swp-card-header>
<swp-card-title>@Model.LabelPerformance</swp-card-title>
<swp-card-title>Omsætning & Belægningsgrad</swp-card-title>
<span class="chart-hint">3 måneder bagud · 3 måneder frem</span>
</swp-card-header>
<swp-stats-row>
<swp-stat-card class="teal">
<swp-stat-value>@Model.BookingsThisYear</swp-stat-value>
<swp-stat-label>@Model.LabelBookingsThisYear</swp-stat-label>
</swp-stat-card>
<swp-stat-card class="purple">
<swp-stat-value>@Model.RevenueThisYear</swp-stat-value>
<swp-stat-label>@Model.LabelRevenueThisYear</swp-stat-label>
</swp-stat-card>
<swp-stat-card class="amber">
<swp-stat-value>@Model.Rating</swp-stat-value>
<swp-stat-label>@Model.LabelAvgRating</swp-stat-label>
</swp-stat-card>
<swp-stat-card>
<swp-stat-value>87%</swp-stat-value>
<swp-stat-label>@Model.LabelOccupancy</swp-stat-label>
</swp-stat-card>
</swp-stats-row>
<swp-chart-container id="employeeRevenueUtilizationChart" style="height: 300px;"></swp-chart-container>
</swp-card>
<swp-card class="stats-bookings">
<!-- Two column layout: Revenue chart + Recent bookings -->
<swp-card>
<swp-card-header>
<swp-card-title>Omsætning (sidste 6 mdr)</swp-card-title>
<swp-chart-legend>
<swp-chart-legend-item>
<swp-chart-legend-dot class="services"></swp-chart-legend-dot>
<span>Services</span>
</swp-chart-legend-item>
<swp-chart-legend-item>
<swp-chart-legend-dot class="products"></swp-chart-legend-dot>
<span>Produkter</span>
</swp-chart-legend-item>
</swp-chart-legend>
</swp-card-header>
<swp-chart-container id="employeeRevenueChart" style="height: 220px;"></swp-chart-container>
</swp-card>
<swp-card class="recent-bookings">
<swp-card-header>
<swp-card-title>Seneste bookinger</swp-card-title>
</swp-card-header>
<swp-data-table id="recentBookingsTable">
<swp-data-table-header>
<swp-data-table-cell>Kunde</swp-data-table-cell>
<swp-data-table-cell>Service</swp-data-table-cell>
<swp-data-table-cell>Dato</swp-data-table-cell>
<swp-data-table-cell>Beløb</swp-data-table-cell>
</swp-data-table-header>
<!-- Rows populated by JavaScript -->
</swp-data-table>
</swp-card>
<!-- Completed Bookings Table -->
<swp-card class="stats-bookings full-width">
<swp-card-header>
<swp-card-title>@Model.LabelCompletedBookings</swp-card-title>
</swp-card-header>
<swp-data-table>
<swp-data-table id="completedBookingsTable">
<swp-data-table-header>
<swp-data-table-cell>@Model.LabelDate</swp-data-table-cell>
<swp-data-table-cell>@Model.LabelTime</swp-data-table-cell>
@ -39,20 +79,7 @@
<swp-data-table-cell>@Model.LabelAmount</swp-data-table-cell>
<swp-data-table-cell>@Model.LabelStatus</swp-data-table-cell>
</swp-data-table-header>
@foreach (var booking in Model.CompletedBookings)
{
<swp-data-table-row>
<swp-data-table-cell>@booking.Date</swp-data-table-cell>
<swp-data-table-cell>@booking.Time</swp-data-table-cell>
<swp-data-table-cell>@booking.Customer</swp-data-table-cell>
<swp-data-table-cell>@booking.Services</swp-data-table-cell>
<swp-data-table-cell>@booking.Duration</swp-data-table-cell>
<swp-data-table-cell>@booking.Amount</swp-data-table-cell>
<swp-data-table-cell>
<swp-status-badge class="@booking.StatusClass">@booking.Status</swp-status-badge>
</swp-data-table-cell>
</swp-data-table-row>
}
<!-- Rows populated by JavaScript -->
</swp-data-table>
</swp-card>
</swp-detail-grid>