using Microsoft.AspNetCore.Mvc; using PlanTempus.Application.Features.Localization.Services; namespace PlanTempus.Application.Features.Customers.Components; public class CustomerDetailStatisticsViewComponent : ViewComponent { private readonly ILocalizationService _localization; public CustomerDetailStatisticsViewComponent(ILocalizationService localization) { _localization = localization; } public IViewComponentResult Invoke(string customerId) { var customer = CustomerDetailCatalog.Get(customerId); var stats = customer.Statistics; // Calculate widths for the attendance bar var total = stats.Attendance.Attended + stats.Attendance.Cancelled + stats.Attendance.NoShow; string attendedWidth, cancelledWidth, noShowWidth; bool allZero = total == 0; if (allZero) { // All zero: gray bar with equal segments attendedWidth = "33.33%"; cancelledWidth = "33.33%"; noShowWidth = "33.34%"; } else { // Calculate percentages, but use 12px minimum for zero values var attendedPercent = stats.Attendance.Attended * 100 / total; var cancelledPercent = stats.Attendance.Cancelled * 100 / total; var noShowPercent = stats.Attendance.NoShow * 100 / total; attendedWidth = stats.Attendance.Attended == 0 ? "12px" : $"{attendedPercent}%"; cancelledWidth = stats.Attendance.Cancelled == 0 ? "12px" : $"{cancelledPercent}%"; noShowWidth = stats.Attendance.NoShow == 0 ? "12px" : $"{noShowPercent}%"; } var model = new CustomerDetailStatisticsViewModel { // Attendance AttendanceTitle = "Fremmøde & Pålidelighed", Attended = stats.Attendance.Attended, AttendedLabel = "Fremmøder", Cancelled = stats.Attendance.Cancelled, CancelledLabel = "Aflysninger", NoShow = stats.Attendance.NoShow, NoShowLabel = "No-shows", ReliabilityPercent = stats.Attendance.ReliabilityPercent, ReliabilityLabel = "Pålidelighed", AttendedWidth = attendedWidth, CancelledWidth = cancelledWidth, NoShowWidth = noShowWidth, AllZero = allZero, // Service patterns ServicePatternsTitle = "Service-mønstre", TopServicesLabel = "Top 3 Services", TopServices = stats.TopServices.Select((s, i) => new TopItemViewModel { Rank = i + 1, Name = s.Name, Count = s.Count }).ToList(), TopProductsLabel = "Top 3 Produkter", TopProducts = stats.TopProducts.Select((p, i) => new TopItemViewModel { Rank = i + 1, Name = p.Name, Count = p.Count }).ToList(), // Booking behavior BookingBehaviorTitle = "Booking-adfærd", AvgBookingNotice = $"{stats.BookingBehavior.AvgBookingNoticeDays} dage", AvgBookingNoticeLabel = "Gns. bookingvarsel", PreferredDay = stats.BookingBehavior.PreferredDay, PreferredDayLabel = "Foretrukken dag", PreferredTimeSlot = stats.BookingBehavior.PreferredTimeSlot, PreferredTimeSlotLabel = "Foretrukken tid", OnlineBookingRate = $"{stats.BookingBehavior.OnlineBookingRate}%", OnlineBookingRateLabel = "Online booking rate", AvgCancellationNotice = $"{stats.BookingBehavior.AvgCancellationNoticeDays} dage", AvgCancellationNoticeLabel = "Gns. aflysningsvarsel", // Loyalty LoyaltyTitle = "Loyalitet", CustomerSinceYears = $"{stats.Loyalty.CustomerSinceYears:0.0} ar".Replace(".", ","), CustomerSinceYearsLabel = "Kunde siden", DaysSinceLastVisit = stats.Loyalty.DaysSinceLastVisit, DaysSinceLastVisitLabel = "Dage siden sidst", ChurnRisk = stats.Loyalty.ChurnRisk, ChurnRiskLabel = "Churn-risiko", AvgIntervalDays = $"{stats.Loyalty.AvgIntervalDays} dage", AvgIntervalDaysLabel = "Gns. interval" }; return View(model); } } public class CustomerDetailStatisticsViewModel { // Attendance public required string AttendanceTitle { get; init; } public int Attended { get; init; } public required string AttendedLabel { get; init; } public int Cancelled { get; init; } public required string CancelledLabel { get; init; } public int NoShow { get; init; } public required string NoShowLabel { get; init; } public int ReliabilityPercent { get; init; } public required string ReliabilityLabel { get; init; } public required string AttendedWidth { get; init; } public required string CancelledWidth { get; init; } public required string NoShowWidth { get; init; } public bool AllZero { get; init; } // Service patterns public required string ServicePatternsTitle { get; init; } public required string TopServicesLabel { get; init; } public List TopServices { get; init; } = new(); public required string TopProductsLabel { get; init; } public List TopProducts { get; init; } = new(); // Booking behavior public required string BookingBehaviorTitle { get; init; } public required string AvgBookingNotice { get; init; } public required string AvgBookingNoticeLabel { get; init; } public required string PreferredDay { get; init; } public required string PreferredDayLabel { get; init; } public required string PreferredTimeSlot { get; init; } public required string PreferredTimeSlotLabel { get; init; } public required string OnlineBookingRate { get; init; } public required string OnlineBookingRateLabel { get; init; } public required string AvgCancellationNotice { get; init; } public required string AvgCancellationNoticeLabel { get; init; } // Loyalty public required string LoyaltyTitle { get; init; } public required string CustomerSinceYears { get; init; } public required string CustomerSinceYearsLabel { get; init; } public int DaysSinceLastVisit { get; init; } public required string DaysSinceLastVisitLabel { get; init; } public required string ChurnRisk { get; init; } public required string ChurnRiskLabel { get; init; } public required string AvgIntervalDays { get; init; } public required string AvgIntervalDaysLabel { get; init; } } public class TopItemViewModel { public int Rank { get; init; } public required string Name { get; init; } public int Count { get; init; } }