Skip to content

Commit

Permalink
#372 - Refactor period selector. Select year in balances.
Browse files Browse the repository at this point in the history
  • Loading branch information
maraf committed Nov 16, 2022
1 parent 2648516 commit 5d1425f
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 73 deletions.
50 changes: 50 additions & 0 deletions src/Money.Blazor.Host/Components/PeriodSelector.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@typeparam T

<button type="button" class="btn btn-primary" @onclick="OpenSelectorAsync">
@Selected?.ToString()
<Icon Identifier="caret-down" />
</button>

@if (Previous != null && Previous.Count > 0)
{
<span class="d-none d-md-inline">
@foreach (var prev in Previous)
{
<a class="btn btn-link" href="@LinkFactory(prev)">
@prev
</a>
}
</span>
}

<Modal @ref="SelectorModal" Title="Select a period" TitleIcon="calendar" BodyCssClass="p-0">
<Loading Context="@Loading">
<LoadingContent>
<div class="p-3">
<i>Loading...</i>
</div>
</LoadingContent>
<ChildContent>
@if (Periods != null)
{
if (Periods.Count > 0)
{
<div class="list-group list-group-flush">
@foreach (var item in Periods)
{
<a @onclick="@(() => SelectorModal.Hide())" href="@LinkFactory(item)" class="list-group-item @(item.Equals(Selected) ? "active" : null)">
@item.ToString()
</a>
}
</div>
}
else
{
<div class="p-3">
<Alert Title="No data." Mode="@AlertMode.Warning" />
</div>
}
}
</ChildContent>
</Loading>
</Modal>
43 changes: 43 additions & 0 deletions src/Money.Blazor.Host/Components/PeriodSelector.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Microsoft.AspNetCore.Components;
using Money.Components.Bootstrap;
using Money.Models.Loading;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Money.Components
{
public partial class PeriodSelector<T>
{
[Parameter]
public T Selected { get; set; }

[Parameter]
public IReadOnlyCollection<T> Previous { get; set; }

[Parameter]
public Func<T, string> LinkFactory { get; set; }

[Parameter]
public Func<Task<IReadOnlyCollection<T>>> ExactGetter { get; set; }

protected LoadingContext Loading { get; } = new LoadingContext();
protected Modal SelectorModal { get; set; }
protected IReadOnlyCollection<T> Periods { get; private set; }

protected async Task LoadAsync()
{
using (Loading.Start())
Periods = await ExactGetter();
}

protected async Task OpenSelectorAsync()
{
SelectorModal.Show();
await LoadAsync();
}
}
}
6 changes: 3 additions & 3 deletions src/Money.Blazor.Host/Layouts/MainMenu.razor
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@
<Online>

<ul class="nav navbar-nav mr-auto mt-3 mt-lg-0 @MenuLeftMarginCssClass">
<MainMenuLink href="@Navigator.UrlSummary()" PageType="@typeof(Pages.SummaryMonth)">
<MainMenuLink href="@Navigator.UrlSummary()" PageType="typeof(Pages.SummaryMonth)">
<Icon Identifier="chart-pie" />
Monthly
</MainMenuLink>
<MainMenuLink Href="@Navigator.UrlSummary(ThisYear)" PageType="@typeof(Pages.SummaryYear)">
<MainMenuLink Href="@Navigator.UrlSummary(ThisYear)" PageType="typeof(Pages.SummaryYear)">
<Icon Identifier="circle" />
Yearly
</MainMenuLink>
<MainMenuLink Href="@Navigator.UrlTrends()">
<Icon Prefix="fas" Identifier="chart-line" />
Trends
</MainMenuLink>
<MainMenuLink Href="@Navigator.UrlBalances(ThisYear)">
<MainMenuLink Href="@Navigator.UrlBalances(ThisYear)" PageType="typeof(Pages.BalancesMonth)">
<Icon Prefix="fas" Identifier="chart-bar" />
Balances
</MainMenuLink>
Expand Down
8 changes: 5 additions & 3 deletions src/Money.Blazor.Host/Pages/BalancesMonth.razor
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@
</ButtonContent>
</Title>

<PeriodSelector Selected="SelectedPeriod" Previous="PeriodGuesses" ExactGetter="GetYearsAsync" LinkFactory="@(year => Navigator.UrlBalances(year))" />

@if (Models == null)
{
<Loading />
}
else
{
<div class="row no-gutters" style="min-width: 440px; height: 400px; height: calc(100vh - 332px)">
<div class="row no-gutters" style="min-width: 440px; height: 400px; height: calc(100vh - 356px)">
@foreach (var model in Models)
{
var expenseSize = model.ExpenseSummary.Value / MaxAmount * 100;
var incomeSize = model.IncomeSummary.Value / MaxAmount * 100;
var expenseSize = MaxAmount == 0 ? 0 : model.ExpenseSummary.Value / MaxAmount * 100;
var incomeSize = MaxAmount == 0 ? 0 : model.IncomeSummary.Value / MaxAmount * 100;

<div class="col-12 col-lg-1 @(model > DateTime.Today ? "text-muted" : String.Empty)">
<div class="d-none d-lg-flex p-1 p-lg-3 h-100 w-100 vertical-bar">
Expand Down
19 changes: 17 additions & 2 deletions src/Money.Blazor.Host/Pages/BalancesMonth.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,27 @@ public partial class BalancesMonth

protected CurrencyFormatter CurrencyFormatter { get; set; }
protected YearModel SelectedPeriod { get; set; }
protected List<YearModel> PeriodGuesses { get; set; }
protected List<MonthBalanceModel> Models { get; set; }
protected decimal MaxAmount { get; set; }

protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();

SelectedPeriod = new YearModel(Year);
CurrencyFormatter = await CurrencyFormatterFactory.CreateAsync();
}

protected async override Task OnParametersSetAsync()
{
await base.OnParametersSetAsync();

SelectedPeriod = new YearModel(Year);
PeriodGuesses = new List<YearModel>(2)
{
SelectedPeriod - 1,
SelectedPeriod - 2,
};

await LoadAsync();
}
Expand All @@ -46,7 +58,7 @@ private async Task LoadAsync()
string defaultCurrency = await Queries.QueryAsync(new FindCurrencyDefault());
var models = await Queries.QueryAsync(new ListMonthBalance(SelectedPeriod));

MaxAmount = models.Max(m => Math.Max(m.IncomeSummary.Value, m.ExpenseSummary.Value));
MaxAmount = models.Count > 0 ? models.Max(m => Math.Max(m.IncomeSummary.Value, m.ExpenseSummary.Value)) : 0;
Models = new List<MonthBalanceModel>();
for (int i = 0; i < 12; i++)
{
Expand All @@ -58,5 +70,8 @@ private async Task LoadAsync()
Models.Add(model);
}
}

protected async Task<IReadOnlyCollection<YearModel>> GetYearsAsync()
=> await Queries.QueryAsync(new ListYearWithOutcome());
}
}
49 changes: 1 addition & 48 deletions src/Money.Blazor.Host/Pages/Summary.razor
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,7 @@
<div class="mb-3">
<SortButton TType="SummarySortType" @bind-Current="@SortDescriptor" Changed="@OnSorted" />

<button type="button" class="btn btn-primary" @onclick="@OpenPeriodSelectorAsync">
@SelectedPeriod.ToString()
<Icon Identifier="caret-down" />
</button>

@if (PeriodGuesses != null && PeriodGuesses.Count > 0)
{
<span class="d-none d-md-inline">
@foreach (var guess in PeriodGuesses)
{
<a class="btn btn-link" href="@UrlSummary(guess)">
@guess
</a>
}
</span>
}
<PeriodSelector Selected="SelectedPeriod" Previous="PeriodGuesses" ExactGetter="GetPeriodsAsync" LinkFactory="UrlSummary" />

<span class="pl-2">
<Loading Context="@CategoriesLoading" />
Expand Down Expand Up @@ -93,36 +78,4 @@
}
</div>
}

<Modal @ref="PeriodSelectorModal" Title="Select a period" TitleIcon="calendar" BodyCssClass="p-0">
<Loading Context="@PeriodsLoading">
<LoadingContent>
<div class="p-3">
<i>Loading...</i>
</div>
</LoadingContent>
<ChildContent>
@if (Periods != null)
{
if (Periods.Count > 0)
{
<div class="list-group list-group-flush">
@foreach (var item in Periods)
{
<a @onclick="@(() => PeriodSelectorModal.Hide())" href="@UrlSummary(item)" class="list-group-item @(item.Equals(SelectedPeriod) ? "active" : null)">
@item.ToString()
</a>
}
</div>
}
else
{
<div class="p-3">
<Alert Title="No data." Message="Let's add some expenses." Mode="@AlertMode.Warning" />
</div>
}
}
</ChildContent>
</Loading>
</Modal>
</div>
27 changes: 10 additions & 17 deletions src/Money.Blazor.Host/Pages/Summary.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public partial class Summary<T> :

protected string SubTitle { get; set; }

protected LoadingContext PeriodsLoading { get; } = new LoadingContext();
protected bool IsPeriodReloadRequired { get; set; }
protected List<T> Periods { get; private set; }
protected T SelectedPeriod { get; set; }
protected IReadOnlyCollection<T> PeriodGuesses { get; set; }
Expand All @@ -69,7 +69,6 @@ public partial class Summary<T> :

protected SortDescriptor<SummarySortType> SortDescriptor { get; set; }

protected Modal PeriodSelectorModal { get; set; }
protected IncomeCreate IncomeCreate { get; set; }

protected override async Task OnInitializedAsync()
Expand Down Expand Up @@ -104,13 +103,15 @@ protected async override Task OnParametersSetAsync()
protected virtual IQuery<List<T>> CreatePeriodsQuery()
=> throw Ensure.Exception.NotImplemented($"Missing override for method '{nameof(CreatePeriodsQuery)}'.");

protected async Task LoadPeriodsAsync(bool isReload = true)
protected async Task<IReadOnlyCollection<T>> GetPeriodsAsync()
{
using (PeriodsLoading.Start())
if (IsPeriodReloadRequired || Periods == null)
{
if (isReload || Periods == null)
Periods = await Queries.QueryAsync(CreatePeriodsQuery());
IsPeriodReloadRequired = false;
Periods = await Queries.QueryAsync(CreatePeriodsQuery());
}

return Periods;
}

protected async Task LoadSelectedPeriodAsync()
Expand Down Expand Up @@ -280,8 +281,8 @@ async Task IEventHandler<IncomeDeleted>.HandleAsync(IncomeDeleted payload)

private async void OnMonthUpdatedEvent(DateTime changed)
{
if (Periods != null && !IsContained(changed))
await LoadPeriodsAsync();
if (!IsContained(changed))
IsPeriodReloadRequired = true;

await LoadSelectedPeriodAsync();
StateHasChanged();
Expand All @@ -298,19 +299,11 @@ private async void OnOutcomeAmountChangedEvent()

private async void OnOutcomeDeletedEvent()
{
if (Periods != null)
await LoadPeriodsAsync();

IsPeriodReloadRequired = true;
await LoadSelectedPeriodAsync();
StateHasChanged();
}

protected async Task OpenPeriodSelectorAsync()
{
PeriodSelectorModal.Show();
await LoadPeriodsAsync(isReload: false);
}

#endregion
}
}

0 comments on commit 5d1425f

Please sign in to comment.