diff --git a/src/Money.Blazor.Host/Pages/ExpenseChecklistMonth.razor b/src/Money.Blazor.Host/Pages/ExpenseChecklistMonth.razor index afb43356..16a1c1b8 100644 --- a/src/Money.Blazor.Host/Pages/ExpenseChecklistMonth.razor +++ b/src/Money.Blazor.Host/Pages/ExpenseChecklistMonth.razor @@ -5,17 +5,25 @@
- +
+
+ + + + +
+ +
@if (Models.Count == 0) diff --git a/src/Money.Blazor.Host/Pages/ExpenseChecklistMonth.razor.cs b/src/Money.Blazor.Host/Pages/ExpenseChecklistMonth.razor.cs index 873f4da3..510a4e83 100644 --- a/src/Money.Blazor.Host/Pages/ExpenseChecklistMonth.razor.cs +++ b/src/Money.Blazor.Host/Pages/ExpenseChecklistMonth.razor.cs @@ -36,6 +36,7 @@ Navigator Navigator public int Month { get; set; } protected MonthModel SelectedPeriod { get; set; } + protected IReadOnlyCollection PeriodGuesses { get; set; } protected List Models { get; set; } = new(); protected LoadingContext Loading { get; set; } = new(); @@ -62,9 +63,15 @@ protected override async Task OnParametersSetAsync() private void EnsureSelectedPeriod() { if (SelectedPeriod == null) + { SelectedPeriod = new MonthModel(Year, Month); + PeriodGuesses = new MonthModel[] { SelectedPeriod - 1, SelectedPeriod - 2 }; + } } + protected async Task> GetMonthsAsync() + => await Queries.QueryAsync(new ListMonthWithExpenseOrIncome()); + private async Task LoadDataAsync() { using (Loading.Start()) diff --git a/src/Money.Blazor.Host/Pages/Overview.razor b/src/Money.Blazor.Host/Pages/Overview.razor index ec0b0a0c..2b50327d 100644 --- a/src/Money.Blazor.Host/Pages/Overview.razor +++ b/src/Money.Blazor.Host/Pages/Overview.razor @@ -25,38 +25,47 @@ var checklistUrl = ChecklistUrl(); var trendsUrl = TrendsSelectedPeriodUrl(); } - @if (incomeUrl != null || trendsUrl != null) - { - + } + @if (Items?.Count > 0) + { + + + + } +
diff --git a/src/Money.Blazor.Host/Pages/Overview.razor.cs b/src/Money.Blazor.Host/Pages/Overview.razor.cs index b6eadc55..93172631 100644 --- a/src/Money.Blazor.Host/Pages/Overview.razor.cs +++ b/src/Money.Blazor.Host/Pages/Overview.razor.cs @@ -45,6 +45,7 @@ public partial class Overview( protected string SubTitle { get; set; } = subTitle; protected T SelectedPeriod { get; set; } + protected IReadOnlyCollection PeriodGuesses { get; set; } protected IKey CategoryKey { get; set; } protected string CategoryName { get; set; } protected List Items { get; set; } @@ -73,6 +74,7 @@ protected async override Task OnParametersSetAsync() { CategoryKey = CreateSelectedCategoryFromParameters(); SelectedPeriod = CreateSelectedItemFromParameters(); + PeriodGuesses = CreatePeriodGuesses(); if (!CategoryKey.IsEmpty) { @@ -96,6 +98,9 @@ protected virtual IKey CreateSelectedCategoryFromParameters() protected virtual T CreateSelectedItemFromParameters() => throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(CreateSelectedItemFromParameters)}'."); + protected virtual IReadOnlyCollection CreatePeriodGuesses() + => throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(CreatePeriodGuesses)}'."); + protected virtual string ListIncomeUrl() => null; @@ -152,6 +157,15 @@ protected async Task LoadDataAsync() protected virtual IQuery> CreateItemsQuery(int pageIndex) => throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(CreateItemsQuery)}'."); + protected virtual IQuery> CreatePeriodsQuery() + => throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(CreatePeriodsQuery)}'."); + + protected async Task> GetPeriodsAsync() + => await Queries.QueryAsync(CreatePeriodsQuery()); + + protected virtual string UrlOverview(T period) + => throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(UrlOverview)}'."); + protected async void OnSortChanged() { Items = null; diff --git a/src/Money.Blazor.Host/Pages/OverviewIncome.razor b/src/Money.Blazor.Host/Pages/OverviewIncome.razor index 0b2c0f8f..17415a27 100644 --- a/src/Money.Blazor.Host/Pages/OverviewIncome.razor +++ b/src/Money.Blazor.Host/Pages/OverviewIncome.razor @@ -10,8 +10,14 @@
- -
diff --git a/src/Money.Blazor.Host/Pages/OverviewIncome.razor.cs b/src/Money.Blazor.Host/Pages/OverviewIncome.razor.cs index f7b74b01..3098ee9e 100644 --- a/src/Money.Blazor.Host/Pages/OverviewIncome.razor.cs +++ b/src/Money.Blazor.Host/Pages/OverviewIncome.razor.cs @@ -39,6 +39,7 @@ public partial class OverviewIncome( protected string SubTitle { get; set; } = subTitle; protected T SelectedPeriod { get; set; } + protected IReadOnlyCollection PeriodGuesses { get; set; } protected List Items { get; set; } protected IncomeCreate CreateModal { get; set; } @@ -68,6 +69,7 @@ protected override void OnParametersSet() base.OnParametersSet(); SelectedPeriod = CreateSelectedItemFromParameters(); + PeriodGuesses = CreatePeriodGuesses(); Reload(); } @@ -80,6 +82,18 @@ protected virtual T CreateSelectedItemFromParameters() protected virtual IQuery> CreateItemsQuery(int pageIndex) => throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(CreateItemsQuery)}'."); + protected virtual IReadOnlyCollection CreatePeriodGuesses() + => throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(CreatePeriodGuesses)}'."); + + protected virtual IQuery> CreatePeriodsQuery() + => throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(CreatePeriodsQuery)}'."); + + protected async Task> GetPeriodsAsync() + => await Queries.QueryAsync(CreatePeriodsQuery()); + + protected virtual string UrlOverviewIncomes(T period) + => throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(UrlOverviewIncomes)}'."); + protected virtual string ListExpenseUrl() => null; diff --git a/src/Money.Blazor.Host/Pages/OverviewMonth.cs b/src/Money.Blazor.Host/Pages/OverviewMonth.cs index 382101a9..6ec0dcb8 100644 --- a/src/Money.Blazor.Host/Pages/OverviewMonth.cs +++ b/src/Money.Blazor.Host/Pages/OverviewMonth.cs @@ -56,6 +56,15 @@ protected override void ClearPreviousParameters() protected override MonthModel CreateSelectedItemFromParameters() => new MonthModel(Year.Value, Month.Value); + protected override IReadOnlyCollection CreatePeriodGuesses() + => new MonthModel[] { SelectedPeriod - 1, SelectedPeriod - 2 }; + + protected override IQuery> CreatePeriodsQuery() + => new ListMonthWithExpenseOrIncome(); + + protected override string UrlOverview(MonthModel period) + => CategoryKey.IsEmpty ? Navigator.UrlOverview(period) : Navigator.UrlOverview(period, CategoryKey); + protected override IKey CreateSelectedCategoryFromParameters() => CategoryGuid != null ? GuidKey.Create(CategoryGuid.Value, KeyFactory.Empty(typeof(Category)).Type) : KeyFactory.Empty(typeof(Category)); diff --git a/src/Money.Blazor.Host/Pages/OverviewMonthIncome.cs b/src/Money.Blazor.Host/Pages/OverviewMonthIncome.cs index 078becbf..47ef3c4c 100644 --- a/src/Money.Blazor.Host/Pages/OverviewMonthIncome.cs +++ b/src/Money.Blazor.Host/Pages/OverviewMonthIncome.cs @@ -40,6 +40,15 @@ protected override void ClearPreviousParameters() protected override MonthModel CreateSelectedItemFromParameters() => new MonthModel(Year.Value, Month.Value); + protected override IReadOnlyCollection CreatePeriodGuesses() + => new MonthModel[] { SelectedPeriod - 1, SelectedPeriod - 2 }; + + protected override IQuery> CreatePeriodsQuery() + => new ListMonthWithExpenseOrIncome(); + + protected override string UrlOverviewIncomes(MonthModel period) + => Navigator.UrlOverviewIncomes(period); + protected override IQuery> CreateItemsQuery(int pageIndex) => new ListMonthIncome(SelectedPeriod, SortDescriptor, pageIndex); diff --git a/src/Money.Blazor.Host/Pages/OverviewYear.cs b/src/Money.Blazor.Host/Pages/OverviewYear.cs index b4b2b98a..261f7a88 100644 --- a/src/Money.Blazor.Host/Pages/OverviewYear.cs +++ b/src/Money.Blazor.Host/Pages/OverviewYear.cs @@ -49,6 +49,15 @@ protected override void ClearPreviousParameters() protected override YearModel CreateSelectedItemFromParameters() => new YearModel(Year.Value); + protected override IReadOnlyCollection CreatePeriodGuesses() + => new YearModel[] { SelectedPeriod - 1, SelectedPeriod - 2 }; + + protected override IQuery> CreatePeriodsQuery() + => new ListYearWithExpenseOrIncome(); + + protected override string UrlOverview(YearModel period) + => CategoryKey.IsEmpty ? Navigator.UrlOverview(period) : Navigator.UrlOverview(period, CategoryKey); + protected override IKey CreateSelectedCategoryFromParameters() => CategoryGuid != null ? GuidKey.Create(CategoryGuid.Value, KeyFactory.Empty(typeof(Category)).Type) : KeyFactory.Empty(typeof(Category)); diff --git a/src/Money.Blazor.Host/Pages/OverviewYearIncome.cs b/src/Money.Blazor.Host/Pages/OverviewYearIncome.cs index d3947f86..0d32d036 100644 --- a/src/Money.Blazor.Host/Pages/OverviewYearIncome.cs +++ b/src/Money.Blazor.Host/Pages/OverviewYearIncome.cs @@ -36,6 +36,15 @@ protected override void ClearPreviousParameters() protected override YearModel CreateSelectedItemFromParameters() => new YearModel(Year.Value); + protected override IReadOnlyCollection CreatePeriodGuesses() + => new YearModel[] { SelectedPeriod - 1, SelectedPeriod - 2 }; + + protected override IQuery> CreatePeriodsQuery() + => new ListYearWithExpenseOrIncome(); + + protected override string UrlOverviewIncomes(YearModel period) + => Navigator.UrlOverviewIncomes(period); + protected override IQuery> CreateItemsQuery(int pageIndex) => new ListYearIncome(SelectedPeriod, SortDescriptor, pageIndex); diff --git a/src/Money.Blazor.Host/Pages/TrendsMonth.razor b/src/Money.Blazor.Host/Pages/TrendsMonth.razor index 94655f75..ed63826d 100644 --- a/src/Money.Blazor.Host/Pages/TrendsMonth.razor +++ b/src/Money.Blazor.Host/Pages/TrendsMonth.razor @@ -1,16 +1,7 @@ @attribute [Authorize] @page "/{Year:int}/trends/{CategoryGuid:guid}" - - <ButtonContent> - <button class="btn btn-secondary" @onclick="(() => Navigator.OpenOverview(SelectedPeriod, CategoryKey))"> - <Icon Prefix="fas" Identifier="list-ul" /> - <span class="d-none d-lg-inline"> - Year overview - </span> - </button> - </ButtonContent> - + @if (Models == null) { @@ -18,10 +9,24 @@ } else { + <div class="d-flex align-items-center mb-3"> + <div> + <PeriodSelector Selected="SelectedPeriod" Previous="PeriodGuesses" ExactGetter="GetYearsAsync" LinkFactory="@(year => Navigator.UrlTrends(year, CategoryKey))" /> + </div> + <ul class="nav nav-pills ps-3"> + <li> + <a class="nav-link" href="@Navigator.UrlOverview(SelectedPeriod, CategoryKey)">Overview</a> + </li> + <li> + <a class="nav-link active" href="@Navigator.UrlTrends(SelectedPeriod, CategoryKey)">Trends</a> + </li> + </ul> + </div> + <div class="row no-gutters" style="min-height: calc(100vh - 312px)"> @foreach (var model in Models) { - var size = model.TotalAmount.Value / MaxAmount * 100; + var size = MaxAmount > 0 ? model.TotalAmount.Value / MaxAmount * 100 : 0; <div class="col-12 col-lg-1 @(model > AppDateTime.Today ? "text-muted" : String.Empty)"> <div class="d-none d-lg-flex p-1 p-lg-3 h-100 w-100 vertical-bar"> diff --git a/src/Money.Blazor.Host/Pages/TrendsMonth.razor.cs b/src/Money.Blazor.Host/Pages/TrendsMonth.razor.cs index dc7f7fc3..b1deb9db 100644 --- a/src/Money.Blazor.Host/Pages/TrendsMonth.razor.cs +++ b/src/Money.Blazor.Host/Pages/TrendsMonth.razor.cs @@ -21,6 +21,7 @@ public partial class TrendsMonth(IQueryDispatcher Queries, Navigator Navigator) public Guid CategoryGuid { get; set; } protected YearModel SelectedPeriod { get; set; } + protected IReadOnlyCollection<YearModel> PeriodGuesses { get; set; } protected IKey CategoryKey { get; set; } protected string CategoryName { get; set; } protected Color CategoryColor { get; set; } @@ -32,6 +33,7 @@ protected override async Task OnInitializedAsync() await base.OnInitializedAsync(); SelectedPeriod = new YearModel(Year); + PeriodGuesses = new YearModel[] { SelectedPeriod - 1, SelectedPeriod - 2 }; CategoryKey = GuidKey.Create(CategoryGuid, KeyFactory.Empty(typeof(Category)).Type); CategoryName = await Queries.QueryAsync(new GetCategoryName(CategoryKey)); CategoryColor = await Queries.QueryAsync(new GetCategoryColor(CategoryKey)); @@ -39,6 +41,9 @@ protected override async Task OnInitializedAsync() await LoadAsync(); } + protected async Task<IReadOnlyCollection<YearModel>> GetYearsAsync() + => await Queries.QueryAsync(new ListYearWithExpenseOrIncome()); + private async Task LoadAsync() { string defaultCurrency = await Queries.QueryAsync(new FindCurrencyDefault());