@page "/summary" @page "/summary/{YearMonth}" @attribute [Authorize] @rendermode InteractiveServer @using System.Globalization @inject global::WorkTracker.Services.WorkDays.IWorkDayService WorkDayService @inject IJSRuntime JS @inject NavigationManager Navigation Monthly Summary

Monthly Summary

@currentMonth.ToString("MMMM yyyy")

Yearly Summary
@if (loading) {

Loading...

} else if (viewMode == SummaryViewMode.Cards && summary is not null) {
Working Days
@summary.TotalWorkingDays
Counted Work Units
@summary.CountedWorkUnits
Total Worked Hours
@FormatHours(summary.TotalWorkedHours)
Preview Hours
@FormatHours(summary.TotalPreviewWorkedHours)
Preview Units
@summary.PreviewWorkUnits
Hours Off
@FormatHours(summary.TotalHoursOff)
Gross Income
€@summary.TotalGrossIncome.ToString("N2")
Net Income
€@summary.TotalNetIncome.ToString("N2")
Office Days
@summary.OfficeDays
Home Days
@summary.HomeDays
Holidays
@summary.HolidayDays
Closure Days
@summary.ClosureDays
Days Off
@summary.DaysOff
Sick Days
@summary.SickDays
} else if (viewMode == SummaryViewMode.Timesheet && timesheet is not null) {
@for (var i = 0; i < timesheet.Days.Count; i++) { var day = timesheet.Days[i]; } @foreach (var row in timesheet.Rows) { @for (var i = 0; i < row.DailyValues.Count; i++) { } }
Categoria
@day.Date.Day
@GetDayHeader(day.Date)
@day.Date.ToString("dddd d MMMM", ItalianCulture)
@if (day.WorkUnitSummaries.Count == 0 && day.EventSummaries.Count == 0) {
Nessun elemento registrato.
} else { @foreach (var workUnit in day.WorkUnitSummaries) {
@workUnit
} @foreach (var calendarEvent in day.EventSummaries) {
@calendarEvent
} }
Totale
@row.Label@FormatTimesheetValue(row.DailyValues[i], row.ValueFormat)@FormatTimesheetValue(row.Total, row.ValueFormat)
} @code { [Parameter] public string? YearMonth { get; set; } private static readonly CultureInfo ItalianCulture = CultureInfo.GetCultureInfo("it-IT"); private const string IncludePreviewPreferenceKey = "worktracker.includePreviewWorkUnits"; private DateOnly currentMonth; private bool loading = true; private bool includePreview; private global::WorkTracker.Domain.MonthlySummaryModel? summary; private global::WorkTracker.Domain.MonthlyTimesheetModel? timesheet; private SummaryViewMode viewMode = SummaryViewMode.Timesheet; protected override async Task OnParametersSetAsync() { currentMonth = ParseCurrentMonth(); await LoadSummary(); } protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) { return; } var savedIncludePreview = await JS.InvokeAsync("workTrackerPreferences.getBool", IncludePreviewPreferenceKey); if (savedIncludePreview.HasValue && savedIncludePreview.Value != includePreview) { includePreview = savedIncludePreview.Value; await LoadSummary(); await InvokeAsync(StateHasChanged); } } private async Task OnIncludePreviewChanged(ChangeEventArgs e) { includePreview = e.Value is bool value && value; await JS.InvokeVoidAsync("workTrackerPreferences.setBool", IncludePreviewPreferenceKey, includePreview); await LoadSummary(); } private async Task LoadSummary() { loading = true; summary = await WorkDayService.GetMonthlySummaryAsync(currentMonth.Year, currentMonth.Month, includePreview); timesheet = await WorkDayService.GetMonthlyTimesheetAsync(currentMonth.Year, currentMonth.Month, includePreview); loading = false; } private Task PreviousMonth() { currentMonth = currentMonth.AddMonths(-1); Navigation.NavigateTo($"/summary/{currentMonth:yyyy-MM}"); return Task.CompletedTask; } private Task NextMonth() { currentMonth = currentMonth.AddMonths(1); Navigation.NavigateTo($"/summary/{currentMonth:yyyy-MM}"); return Task.CompletedTask; } private void SetViewMode(SummaryViewMode mode) { viewMode = mode; } private static string GetDayHeader(DateOnly date) { return ItalianCulture.TextInfo.ToTitleCase(date.ToString("ddd", ItalianCulture)); } private DateOnly ParseCurrentMonth() { if (!string.IsNullOrEmpty(YearMonth) && DateTime.TryParseExact(YearMonth, "yyyy-MM", null, DateTimeStyles.None, out var parsed)) { return new DateOnly(parsed.Year, parsed.Month, 1); } return new DateOnly(DateTime.Today.Year, DateTime.Today.Month, 1); } private static string GetDayColumnClass(global::WorkTracker.Domain.MonthlyTimesheetDayModel day) { if (day.IsWeekend || day.IsHoliday) { return "timesheet-summary-day-danger"; } return day.IsClosure ? "timesheet-summary-day-closure" : string.Empty; } private static string GetDayPopupClass(int index, int totalDays) { if (index == 0) { return "timesheet-summary-day-popup-left"; } return index >= totalDays - 2 ? "timesheet-summary-day-popup-right" : string.Empty; } private static string FormatTimesheetValue(decimal? value, global::WorkTracker.Domain.MonthlyTimesheetValueFormat valueFormat) { if (!value.HasValue || value.Value <= 0m) { return string.Empty; } return valueFormat == global::WorkTracker.Domain.MonthlyTimesheetValueFormat.Days ? value.Value.ToString("0.##", ItalianCulture) : FormatDecimalHours(value.Value); } private static string FormatDecimalHours(decimal value) { return DurationFormatter.FormatHours(value, blankWhenZero: true); } private static string FormatHours(decimal value) { return DurationFormatter.FormatHours(value); } private enum SummaryViewMode { Cards, Timesheet } }