From f88ed54295ed063f45a6150ff55fe85e0705d038 Mon Sep 17 00:00:00 2001 From: Simon Schulze Date: Mon, 17 Jun 2024 23:54:47 +0200 Subject: [PATCH 1/7] Add option to display standings race-by-race --- .../Standings/DisplayStanding.razor | 104 ++++++++++-------- .../Standings/RaceByRacePoints.razor | 74 +++++++++++++ .../Standings/RaceByRacePoints.razor.css | 19 ++++ src/iRLeagueManager.Web/Pages/Standings.razor | 6 +- .../iRLeagueManager.Web.csproj | 4 +- 5 files changed, 157 insertions(+), 50 deletions(-) create mode 100644 src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor create mode 100644 src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor.css diff --git a/src/iRLeagueManager.Web/Components/Standings/DisplayStanding.razor b/src/iRLeagueManager.Web/Components/Standings/DisplayStanding.razor index 653ecfe8..767c1ea9 100644 --- a/src/iRLeagueManager.Web/Components/Standings/DisplayStanding.razor +++ b/src/iRLeagueManager.Web/Components/Standings/DisplayStanding.razor @@ -6,50 +6,64 @@ var showDriver = HasDriver(Standing.StandingRows) && Standing.IsTeamStanding == false; var hasTeam = HasTeam(Standing.StandingRows); } - - - - @if (showDriver) - { - - } - @if (hasTeam) - { - - } - - - - - - - - - - - - @if (showDriver) - { - @Row.Firstname @Row.Lastname - } - @if (hasTeam) - { - @Row.TeamName - } - - - @(Row.PenaltyPoints != 0 ? "-" : "")@Row.PenaltyPoints - - - - @Row.RacesCounted@(Row.RacesCounted != Row.Races ? $" ({Row.Races})" : "") - - - - @Row.Top3 - @Row.Incidents - - + + + + Show race-by-race + + + + @if (showRaceByRace) + { + + } + else + { + + + + @if (showDriver) + { + + } + @if (hasTeam) + { + + } + + + + + + + + + + + + @if (showDriver) + { + @Row.Firstname @Row.Lastname + } + @if (hasTeam) + { + @Row.TeamName + } + + + @(Row.PenaltyPoints != 0 ? "-" : "")@Row.PenaltyPoints + + + + @Row.RacesCounted@(Row.RacesCounted != Row.Races ? $" ({Row.Races})" : "") + + + + @Row.Top3 + @Row.Incidents + + + } @code { @@ -58,6 +72,8 @@ [Parameter, EditorRequired] public StandingsModel Standing { get; set; } = default!; + private bool showRaceByRace = false; + private bool HasDriver(IEnumerable rows) { return rows.Any(x => x.MemberId != null); diff --git a/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor b/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor new file mode 100644 index 00000000..906c339f --- /dev/null +++ b/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor @@ -0,0 +1,74 @@ +@namespace iRLeagueManager.Web.Components +@using iRLeagueApiCore.Common.Models +@using iRLeagueApiCore.Common.Models.Standings + + + @{ + var columnsCount = RaceColumns ?? StandingRows.Select(x => x.ResultRows.Count()).Max(); + } + + + + Pos. + + + Name + + @for (int i = 1; i <= columnsCount; i++) + { + + R@(i.ToString()) + + } + + + @foreach (var row in StandingRows) + { + var columns = row.ResultRows.ToList(); + if (columnsCount > columns.Count) + { + columns.AddRange(Enumerable.Repeat(null, columns.Count - columnsCount)); + }; + + + + @(row.Position). + + + @row.Firstname @row.Lastname + + @foreach (var race in columns) + { + + @race?.TotalPoints + + } + + + @foreach (var race in columns) + { + + @race?.RacePoints + + + @race?.BonusPoints + + + @(race?.PenaltyPoints is < 0 or > 0 ? "-" : "")@race?.PenaltyPoints + + } + + + } + + +@code { + [Parameter] public IEnumerable StandingRows { get; set; } = default!; + [Parameter] public int? RaceColumns { get; set; } + + protected override void OnParametersSet() + { + base.OnParametersSet(); + BlazorParameterNullException.ThrowIfNull(this, StandingRows); + } +} diff --git a/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor.css b/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor.css new file mode 100644 index 00000000..d76f3934 --- /dev/null +++ b/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor.css @@ -0,0 +1,19 @@ +.mud-simple-table .mud-table-container table tbody tr:last-child { + border-bottom: 1px solid var(--mud-palette-table-lines); +} + +.mud-simple-table .mud-table-container table tbody:hover { + background-color: var(--mud-palette-table-hover) !important; +} + +.mud-simple-table .mud-table-container table tbody:nth-of-type(2n+1):not(:hover) { + background-color: var(--mud-palette-table-striped); +} + +.mud-simple-table .mud-table-container table tbody:nth-child(2n+1):not(:hover) tr:nth-child(2n+1) td:nth-child(2n+3), +.mud-simple-table .mud-table-container table tbody:nth-child(2n+1):not(:hover) tr:nth-child(2n) td:nth-child(6n+3), +.mud-simple-table .mud-table-container table tbody:nth-child(2n+1):not(:hover) tr:nth-child(2n) td:nth-child(6n+2), +.mud-simple-table .mud-table-container table tbody:nth-child(2n+1):not(:hover) tr:nth-child(2n) td:nth-child(6n+1) { + background-color: var(--mud-palette-table-striped); + filter: brightness(85%); +} \ No newline at end of file diff --git a/src/iRLeagueManager.Web/Pages/Standings.razor b/src/iRLeagueManager.Web/Pages/Standings.razor index bd907836..e4ef1e56 100644 --- a/src/iRLeagueManager.Web/Pages/Standings.razor +++ b/src/iRLeagueManager.Web/Pages/Standings.razor @@ -41,9 +41,7 @@ @foreach ((var standing, var i) in @Bind(vm, x => x.Standings).Select((x, i) => (x, i))) { - - - + } @@ -51,7 +49,7 @@ else { var standing = vm.Standings.First(); - + } } diff --git a/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj b/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj index 5e42610b..db64cd71 100644 --- a/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj +++ b/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj @@ -33,8 +33,8 @@ - - + + From 9c98e26f5503ff70631e3ed8ebc963bb55904d3a Mon Sep 17 00:00:00 2001 From: Simon Schulze Date: Tue, 18 Jun 2024 00:03:07 +0200 Subject: [PATCH 2/7] Highlight drop weeks --- .../Components/Standings/RaceByRacePoints.razor | 8 ++++---- .../Components/Standings/RaceByRacePoints.razor.css | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor b/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor index 906c339f..e0e0ac21 100644 --- a/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor +++ b/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor @@ -39,7 +39,7 @@ @foreach (var race in columns) { - + @race?.TotalPoints } @@ -47,13 +47,13 @@ @foreach (var race in columns) { - + @race?.RacePoints - + @race?.BonusPoints - + @(race?.PenaltyPoints is < 0 or > 0 ? "-" : "")@race?.PenaltyPoints } diff --git a/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor.css b/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor.css index d76f3934..4f5a5a55 100644 --- a/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor.css +++ b/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor.css @@ -16,4 +16,8 @@ .mud-simple-table .mud-table-container table tbody:nth-child(2n+1):not(:hover) tr:nth-child(2n) td:nth-child(6n+1) { background-color: var(--mud-palette-table-striped); filter: brightness(85%); +} + +.mud-simple-table .mud-table-container table tbody tr td.dropped { + color: var(--mud-palette-text-disabled); } \ No newline at end of file From 692cc1f57a6d1d6528e534623c5cc3eda320e3af Mon Sep 17 00:00:00 2001 From: Simon Schulze Date: Tue, 18 Jun 2024 20:03:06 +0200 Subject: [PATCH 3/7] add Dockerfile --- src/iRLeagueManager.Web/Dockerfile | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/iRLeagueManager.Web/Dockerfile diff --git a/src/iRLeagueManager.Web/Dockerfile b/src/iRLeagueManager.Web/Dockerfile new file mode 100644 index 00000000..d1207cc2 --- /dev/null +++ b/src/iRLeagueManager.Web/Dockerfile @@ -0,0 +1,17 @@ +FROM mcr.microsoft.com/dotnet/sdk:7.0 as build +WORKDIR /source + +# copy csproj and restore as distinct layers +COPY *.csproj . +RUN dotnet restore + +# copy and publish app and libraries +COPY . . +RUN dotnet publish -o /app + +# final stage/image +FROM mcr.microsoft.com/dotnet/sdk:7.0 +WORKDIR /app +COPY --from=build /app . +USER $APP_UID +ENTRYPOINT ["./iRLeagueManager.Web"] \ No newline at end of file From c9b74f7eb966097c71d58bd90da708dd5e086bda Mon Sep 17 00:00:00 2001 From: Simon Schulze Date: Fri, 12 Jul 2024 15:58:28 +0200 Subject: [PATCH 4/7] Implement dialog to change teams for previous results --- .../Components/EventSelect.razor | 2 +- .../Components/Results/DisplayResult.razor | 30 +- .../Components/Teams/ChangeTeamsDialog.razor | 80 +++++ .../Teams/ChangeTeamsDialog.razor.cs | 302 ++++++++++++++++++ .../Data/LeagueApiService.cs | 4 +- .../Helpers/DateTimeUtils.cs | 9 + src/iRLeagueManager.Web/Pages/Results.razor | 184 +++++------ src/iRLeagueManager.Web/Program.cs | 15 +- .../Shared/UtilityComponentBase.cs | 25 ++ .../ViewModels/LeagueViewModelBase.cs | 6 + src/iRLeagueManager.Web/appsettings.json | 4 +- .../iRLeagueManager.Web.csproj | 4 +- 12 files changed, 557 insertions(+), 108 deletions(-) create mode 100644 src/iRLeagueManager.Web/Components/Teams/ChangeTeamsDialog.razor create mode 100644 src/iRLeagueManager.Web/Components/Teams/ChangeTeamsDialog.razor.cs create mode 100644 src/iRLeagueManager.Web/Helpers/DateTimeUtils.cs diff --git a/src/iRLeagueManager.Web/Components/EventSelect.razor b/src/iRLeagueManager.Web/Components/EventSelect.razor index 8bf02f3c..2d88e4ce 100644 --- a/src/iRLeagueManager.Web/Components/EventSelect.razor +++ b/src/iRLeagueManager.Web/Components/EventSelect.razor @@ -154,7 +154,7 @@ return null; } index ??= EventList.EventList.IndexOf(@event); - return $"{(index + 1).Value.ToString("00")}. {@event.Date.GetValueOrDefault().ToString("dd.MM.yy")}: {@event.TrackName}" + (@event.ConfigName != "-" ? $" - {@event.ConfigName}" : ""); + return $"{(index + 1).Value.ToString("00")}. {@event.Date.GetValueOrDefault().ToShortDateFormatted()}: {@event.TrackName}" + (@event.ConfigName != "-" ? $" - {@event.ConfigName}" : ""); } public void Dispose() diff --git a/src/iRLeagueManager.Web/Components/Results/DisplayResult.razor b/src/iRLeagueManager.Web/Components/Results/DisplayResult.razor index 8a7131cc..57cfb0c6 100644 --- a/src/iRLeagueManager.Web/Components/Results/DisplayResult.razor +++ b/src/iRLeagueManager.Web/Components/Results/DisplayResult.razor @@ -117,6 +117,7 @@ Add Bonus/Penalty Show Bonuses/Penalties + Change Team } @@ -127,6 +128,8 @@ @code { [CascadingParameter] private EventListViewModel EventList { get; set; } = default!; + [CascadingParameter] + private ResultsPageViewModel? ResultsPageVm { get; set; } [Parameter, EditorRequired] public SessionResultViewModel Result { get; set; } = default!; [Parameter] @@ -143,7 +146,7 @@ protected override void OnParametersSet() { base.OnParametersSet(); - BlazorParameterNullException.ThrowIfNull(this, EventList); + BlazorParameterNullException.ThrowIfNull(this, EventList, cascading: true); BlazorParameterNullException.ThrowIfNull(this, Result); isTeamResult = Result.ResultRows.Any(x => x.MemberId == null); showDisqualification = Result.ResultRows.Any(x => x.Status == RaceStatus.Disqualified); @@ -220,4 +223,29 @@ }; await DialogService.Show("Bonuses/Penalties", parameters, options).Result; } + + private async Task ChangeTeamClick(ResultRowModel? row) + { + if (row is null) + { + return; + } + + var parameters = new DialogParameters() + { + { x => x.Member, new() { FirstName = row.Firstname, LastName = row.Lastname, MemberId = row.MemberId.GetValueOrDefault() }}, + }; + + await DialogService.Show("Change Team", parameters).Result; + await Refresh(); + } + + private async Task Refresh() + { + if (ResultsPageVm?.SelectedEvent is null) + { + return; + } + await ResultsPageVm.LoadFromEventAsync(ResultsPageVm.SelectedEvent.EventId); + } } diff --git a/src/iRLeagueManager.Web/Components/Teams/ChangeTeamsDialog.razor b/src/iRLeagueManager.Web/Components/Teams/ChangeTeamsDialog.razor new file mode 100644 index 00000000..d664cb20 --- /dev/null +++ b/src/iRLeagueManager.Web/Components/Teams/ChangeTeamsDialog.razor @@ -0,0 +1,80 @@ +@namespace iRLeagueManager.Web.Components +@inherits UtilityComponentBase + + + + + + @* Driver Info *@ + + @Member.FirstName @Member.LastName + + + @* Select new Team *@ + + + + @* Select Season *@ + + @foreach (var season in ApiService.Shared.SeasonList) + { + + @season.SeasonName + + } + + + + @* Result/Team table *@ + + + + Race + Team + + + + + + + + + @Row.RaceNr. - @Row.Date.ToShortDateFormatted() + @Row.TrackName + + + @Row.Team?.Name + + @switch (Row.State) + { + case ChangeTeamState.ToChange: + + break; + case ChangeTeamState.Changing: + + break; + case ChangeTeamState.Changed: + + break; + default: + break; + } + + + + + + + Close + Apply + + diff --git a/src/iRLeagueManager.Web/Components/Teams/ChangeTeamsDialog.razor.cs b/src/iRLeagueManager.Web/Components/Teams/ChangeTeamsDialog.razor.cs new file mode 100644 index 00000000..0f0fb62d --- /dev/null +++ b/src/iRLeagueManager.Web/Components/Teams/ChangeTeamsDialog.razor.cs @@ -0,0 +1,302 @@ +using iRLeagueApiCore.Common.Models; +using iRLeagueManager.Web.Data; +using iRLeagueManager.Web.Exceptions; +using iRLeagueManager.Web.Extensions; +using iRLeagueManager.Web.Pages; +using iRLeagueManager.Web.Shared; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using MudBlazor; + +namespace iRLeagueManager.Web.Components; + +public partial class ChangeTeamsDialog : UtilityComponentBase +{ + [Inject] + private LeagueApiService ApiService { get; set; } = default!; + + + [CascadingParameter] + MudDialogInstance ModalInstance { get; set; } = default!; + [Parameter] + public MemberInfoModel Member { get; set; } = default!; + [Parameter] + public SeasonModel? InitialSeason { get; set; } + + private bool selectWholeSeason = false; + + private TeamInfoModel? newTeam; + + private TeamInfoModel? currentTeam; + + public IEnumerable Teams { get; set; } = []; + + private SeasonModel season = default!; + private SeasonModel Season + { + get => season; + set + { + if (season != value) + { + season = value; + InvokeAsync(SeasonChanged); + } + } + } + + private enum ChangeTeamState + { + NoAction = 0, + ToChange, + Changing, + Changed, + }; + + private class SelectResultTeam + { + public long EventId { get; set; } + public bool Selected { get; set; } = false; + public TeamInfoModel? Team { get; set; } + public int RaceNr { get; set; } + public DateTime Date { get; set; } + public string TrackName { get; set; } = string.Empty; + public string ConfigName { get; set; } = string.Empty; + public ChangeTeamState State { get; set; } + } + + private IEnumerable memberTeamResults = []; + + private bool CanSubmit => memberTeamResults.Any(x => (x.Selected || selectWholeSeason) && x.Team?.TeamId != newTeam?.TeamId); + + protected override void OnParametersSet() + { + base.OnParametersSet(); + BlazorParameterNullException.ThrowIfNull(this, ModalInstance, cascading: true); + BlazorParameterNullException.ThrowIfNull(this, Member); + + season = InitialSeason ?? ApiService.Shared.SeasonList + .FirstOrDefault(x => x.SeasonId == ApiService.Shared.SeasonId) + ?? new(); + } + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + await base.OnAfterRenderAsync(firstRender); + if (firstRender == false) + { + return; + } + await LoadTeams(); + await LoadSeasonResults(season.SeasonId); + } + + private async Task SeasonChanged() + { + await LoadSeasonResults(Season.SeasonId); + } + + private async Task LoadSeasonResults(long seasonId) + { + if (ApiService.CurrentLeague is null) + { + return LeagueNullResult(); + } + + try + { + Loading = true; + + var request = ApiService.CurrentLeague.Seasons() + .WithId(seasonId) + .Results(); + var result = await request.Get(CancellationToken); + + if (result.Success && result.Content is IEnumerable eventResults) + { + memberTeamResults = eventResults + .Select((x, i) => MapToMemberTeamResult(x, i)) + .NotNull() + .ToList(); + newTeam = currentTeam = memberTeamResults.LastOrDefault() + ?.Team; + await InvokeAsync(StateHasChanged); + } + + return result.ToStatusResult(); + } + finally + { + Loading = false; + } + } + + private async Task LoadTeams() + { + if (ApiService.CurrentLeague is null) + { + return LeagueNullResult(); + } + + try + { + Loading = true; + var result = await ApiService.CurrentLeague.Teams().Get(); + if (result.Success && result.Content is IEnumerable teams) + { + Teams = teams.Select(x => new TeamInfoModel() + { + Name = x.Name, + TeamColor = x.TeamColor, + TeamId = x.TeamId, + }); + } + return result.ToStatusResult(); + } + finally + { + Loading = false; + } + } + + private async Task ChangeTeam(SelectResultTeam selectResult) + { + if (ApiService.CurrentLeague is null) + { + return LeagueNullResult(); + } + + try + { + Loading = true; + + // Todo: Modify result rows for event + // 1. try fetching raw event result + var rawResultRequest = await ApiService.CurrentLeague + .Events() + .WithId(selectResult.EventId) + .Results() + .Raw() + .Get(CancellationToken); + if (rawResultRequest.Success == false || rawResultRequest.Content is not RawEventResultModel rawEventResult) + { + return rawResultRequest.ToStatusResult(); + } + + // 2. Get member result rows that need team updated + var rows = rawEventResult.SessionResults + .SelectMany(x => x.ResultRows) + .Where(x => x.MemberId == Member.MemberId) + .ToList(); + + // 3. update team and send update request + foreach (var (row, index) in rows.WithIndex()) + { + row.TeamId = newTeam?.TeamId; + var modRowRequest = await ApiService.CurrentLeague + .Results() + .ModifyResultRow(row.ResultRowId) + .Put(row, CancellationToken); + } + + return StatusResult.SuccessResult(); + } + finally + { + Loading = false; + } + } + + private async Task TriggerCalculation(long eventId) + { + if (ApiService.CurrentLeague is null) + { + return LeagueNullResult(); + } + + try + { + Loading = false; + var request = await ApiService.CurrentLeague + .Events() + .WithId(eventId) + .Results() + .Calculate() + .Post(CancellationToken); + return request.ToStatusResult(); + } + finally + { + Loading = true; + } + } + + private SelectResultTeam? MapToMemberTeamResult(SeasonEventResultModel? seasonEventResult, int index) + { + var eventResult = seasonEventResult?.EventResults.FirstOrDefault(); + if (eventResult == null) + { + return null; + } + + var row = eventResult.SessionResults + .SelectMany(x => x.ResultRows) + .FirstOrDefault(x => x.MemberId == Member.MemberId); + if (row == null) + { + return null; + } + + var team = Teams.FirstOrDefault(x => x.TeamId == row.TeamId); + return new() + { + EventId = eventResult.EventId, + RaceNr = index + 1, + Team = team, + Date = eventResult.Date, + TrackName = eventResult.TrackName, + ConfigName = eventResult.ConfigName, + }; + } + + private async Task> SearchTeam(string term) + { + if (string.IsNullOrEmpty(term)) + { + return await Task.FromResult(Teams); + } + + var separatedTerms = term.Split(' ', ',') + .NotNull(); + return Teams + .Where(team => separatedTerms.Any(x => team.Name.Contains(x, StringComparison.OrdinalIgnoreCase))) + .Cast(); + } + + private async Task Submit() + { + IEnumerable updateResults = updateResults = memberTeamResults + .Where(x => (x.Selected || selectWholeSeason) && x.Team?.TeamId != newTeam?.TeamId); + foreach (var result in updateResults) + { + result.State = ChangeTeamState.ToChange; + } + foreach (var result in updateResults) + { + result.State = ChangeTeamState.Changing; + await InvokeAsync(StateHasChanged); + await ChangeTeam(result); + await Task.Delay(200); + result.State = ChangeTeamState.Changed; + await InvokeAsync(StateHasChanged); + await TriggerCalculation(result.EventId); + } + await Task.Delay(2000); + await LoadSeasonResults(Season.SeasonId); + } +} diff --git a/src/iRLeagueManager.Web/Data/LeagueApiService.cs b/src/iRLeagueManager.Web/Data/LeagueApiService.cs index 520ccc54..05ced6f7 100644 --- a/src/iRLeagueManager.Web/Data/LeagueApiService.cs +++ b/src/iRLeagueManager.Web/Data/LeagueApiService.cs @@ -10,18 +10,16 @@ public sealed class LeagueApiService { //private readonly ILogger logger; - public LeagueApiService(ILeagueApiClient apiClient, SharedStateService sharedState, ClientLocalTimeProvider localTimeProvider, JsonSerializerOptions jsonOptions) + public LeagueApiService(ILeagueApiClient apiClient, SharedStateService sharedState, ClientLocalTimeProvider localTimeProvider) { //this.logger = logger; Client = apiClient; Shared = sharedState; - JsonOptions = jsonOptions; ClientTimeProvider= localTimeProvider; } public ILeagueApiClient Client { get; } public SharedStateService Shared { get; } - public JsonSerializerOptions JsonOptions { get; } public ClientLocalTimeProvider ClientTimeProvider { get; } public ILeagueByNameEndpoint? CurrentLeague { get; private set; } public ISeasonByIdEndpoint? CurrentSeason { get; private set; } diff --git a/src/iRLeagueManager.Web/Helpers/DateTimeUtils.cs b/src/iRLeagueManager.Web/Helpers/DateTimeUtils.cs new file mode 100644 index 00000000..e0a5b7db --- /dev/null +++ b/src/iRLeagueManager.Web/Helpers/DateTimeUtils.cs @@ -0,0 +1,9 @@ +namespace iRLeagueManager.Web.Helpers; + +internal static class DateTimeUtils +{ + public static string ToShortDateFormatted(this DateTime dateTime) + { + return dateTime.ToString("dd.MM.yy"); + } +} diff --git a/src/iRLeagueManager.Web/Pages/Results.razor b/src/iRLeagueManager.Web/Pages/Results.razor index 9e754837..d561b209 100644 --- a/src/iRLeagueManager.Web/Pages/Results.razor +++ b/src/iRLeagueManager.Web/Pages/Results.razor @@ -18,104 +18,106 @@ Results - @LeagueName - - x.Loading)> - - Results - - - - - - - @if (vm.SelectedEvent?.HasResult == true && SharedState.SeasonFinished == false) - { - - Calculate - - @if (vm.Results.Count > 0) + + + x.Loading)> + + Results + + + + + + + @if (vm.SelectedEvent?.HasResult == true && SharedState.SeasonFinished == false) { - - - - } - } - - - - - - - - @if (@Bind(vm, x => x.Results)?.Count == 0) - { - - No Results - - } - else - { - @if (vm.Results.Count > 1) - { - - @foreach ((var eventResult, var i) in @Bind(vm, x => x.Results).Select((x, i) => (x, i))) - { - - - @foreach (var result in @Bind(eventResult, x => x.SessionResults).OrderByDescending(x => x.SessionNr)) + + Calculate + + @if (vm.Results.Count > 0) { - - - - - - - - + + + } - - - } - - } - else + } + + + + + + + + @if (@Bind(vm, x => x.Results)?.Count == 0) { - var eventResult = vm.Results.First(); - - @foreach (var result in @Bind(eventResult, x => x.SessionResults).OrderByDescending(x => x.SessionNr)) - { - - - - - - - - - } - + + No Results + } - } - - - - - @if (SharedState.SeasonFinished == false) + else { - - Upload Result - Fetch from SubsessionId - + @if (vm.Results.Count > 1) + { + + @foreach ((var eventResult, var i) in @Bind(vm, x => x.Results).Select((x, i) => (x, i))) + { + + + @foreach (var result in @Bind(eventResult, x => x.SessionResults).OrderByDescending(x => x.SessionNr)) + { + + + + + + + + + } + + + } + + } + else + { + var eventResult = vm.Results.First(); + + @foreach (var result in @Bind(eventResult, x => x.SessionResults).OrderByDescending(x => x.SessionNr)) + { + + + + + + + + + } + + } } - - - + + + + + @if (SharedState.SeasonFinished == false) + { + + Upload Result + Fetch from SubsessionId + + } + + + + @code { private const string resultTabParam = "resultTab"; diff --git a/src/iRLeagueManager.Web/Program.cs b/src/iRLeagueManager.Web/Program.cs index 26d5d6ef..719ca8e7 100644 --- a/src/iRLeagueManager.Web/Program.cs +++ b/src/iRLeagueManager.Web/Program.cs @@ -30,14 +30,13 @@ builder.Services.AddMvvm(); builder.Services.AddLeagueApiService(); -builder.Services.AddScoped(configure => -{ - var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); - jsonOptions.Converters.Add(new JsonStringEnumConverter()); - jsonOptions.Converters.Add(new JsonTimeSpanConverter()); - jsonOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; - return jsonOptions; -}); +//builder.Services.AddScoped(configure => +//{ +// var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); +// jsonOptions.Converters.Add(new JsonStringEnumConverter()); +// jsonOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; +// return jsonOptions; +//}); builder.Services.AddLeagueApiClient(config => config .UseBaseAddress(builder.Configuration["APIServer"] ?? string.Empty) diff --git a/src/iRLeagueManager.Web/Shared/UtilityComponentBase.cs b/src/iRLeagueManager.Web/Shared/UtilityComponentBase.cs index 42ccb331..4cc3dc62 100644 --- a/src/iRLeagueManager.Web/Shared/UtilityComponentBase.cs +++ b/src/iRLeagueManager.Web/Shared/UtilityComponentBase.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Routing; using Microsoft.JSInterop; +using MudBlazor; using MvvmBlazor.Components; using System.Net; using System.Threading; @@ -27,6 +28,20 @@ public class UtilityComponentBase : MvvmComponentBase private IDisposable? locationChangingHandler; + private bool loading; + public bool Loading + { + get => loading; + protected set + { + if (loading != value) + { + loading = value; + Shared.LoadingCount += loading ? 1 : -1; + } + } + } + protected override void OnInitialized() { base.OnInitialized(); @@ -48,6 +63,7 @@ protected override void Dispose(bool disposing) cancellationTokenSource.Dispose(); Shared.StateChanged -= SharedStateChanged; NavigationManager.LocationChanged -= OnLocationChanged; + Loading = false; } base.Dispose(disposing); @@ -161,4 +177,13 @@ protected string GetReturnUrl() } return WebUtility.UrlEncode(returnUrl); } + + protected static StatusResult LeagueNullResult() => + StatusResult.FailedResult("League Null", $"{nameof(LeagueApiService)}.{nameof(LeagueApiService.CurrentLeague)} was null", []); + + protected static StatusResult SeasonNullResult() => + StatusResult.FailedResult("Season Null", $"{nameof(LeagueApiService)}.{nameof(LeagueApiService.CurrentSeason)} was null", []); + + protected static StatusResult LeagueNullResult(T? content = default) => + StatusResult.FailedResult("League Null", content, $"{nameof(LeagueApiService)}.{nameof(LeagueApiService.CurrentSeason)}", []); } diff --git a/src/iRLeagueManager.Web/ViewModels/LeagueViewModelBase.cs b/src/iRLeagueManager.Web/ViewModels/LeagueViewModelBase.cs index 8fee675d..88ac91e7 100644 --- a/src/iRLeagueManager.Web/ViewModels/LeagueViewModelBase.cs +++ b/src/iRLeagueManager.Web/ViewModels/LeagueViewModelBase.cs @@ -113,6 +113,12 @@ protected virtual void Dispose(bool disposing) { disposedValue = true; } + + if (!disposing) + { + Cts.Dispose(); + Loading = false; + } } public void Dispose() diff --git a/src/iRLeagueManager.Web/appsettings.json b/src/iRLeagueManager.Web/appsettings.json index bc04f2c2..8813a99e 100644 --- a/src/iRLeagueManager.Web/appsettings.json +++ b/src/iRLeagueManager.Web/appsettings.json @@ -9,8 +9,8 @@ } }, "AllowedHosts": "*", - //"APIServer": "http://localhost:5000", - "APIServer": "https://irleaguemanager.net/api/", + "APIServer": "http://localhost:5000", + //"APIServer": "https://irleaguemanager.net/api/", "DefaultUser": "testuser", "DefaultPassword": "TestPass123!" } diff --git a/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj b/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj index db64cd71..c95100ca 100644 --- a/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj +++ b/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj @@ -33,8 +33,8 @@ - - + + From f2f1dfe8540d1a49b11ba4c8ca34d52b5730025d Mon Sep 17 00:00:00 2001 From: Simon Schulze Date: Fri, 12 Jul 2024 16:13:05 +0200 Subject: [PATCH 5/7] Small cleanup and fixes - remove comments - fix dialogs close on enter --- .../Components/Events/EditEventDialog.razor | 5 ++--- .../Components/Reviews/EditCommentDialog.razor | 2 +- .../Components/Reviews/EditReviewDialog.razor | 4 ++-- .../Components/Reviews/EditReviewResultDialog.razor | 4 ++-- src/iRLeagueManager.Web/Data/LeagueApiService.cs | 3 --- src/iRLeagueManager.Web/Data/LeeagueModel.cs | 5 ----- src/iRLeagueManager.Web/Pages/Schedules.razor | 1 - src/iRLeagueManager.Web/Program.cs | 11 ----------- 8 files changed, 7 insertions(+), 28 deletions(-) delete mode 100644 src/iRLeagueManager.Web/Data/LeeagueModel.cs diff --git a/src/iRLeagueManager.Web/Components/Events/EditEventDialog.razor b/src/iRLeagueManager.Web/Components/Events/EditEventDialog.razor index 969c645d..bb2c670a 100644 --- a/src/iRLeagueManager.Web/Components/Events/EditEventDialog.razor +++ b/src/iRLeagueManager.Web/Components/Events/EditEventDialog.razor @@ -5,10 +5,9 @@ @using iRLeagueApiCore.Common.Models.Tracks @using iRLeagueManager.Web.ViewModels @inherits EditDialogBase -@inject JsonSerializerOptions jsonOptions @inject TrackListService trackListService - + @@ -106,7 +105,7 @@ Cancel - Save + Save diff --git a/src/iRLeagueManager.Web/Components/Reviews/EditCommentDialog.razor b/src/iRLeagueManager.Web/Components/Reviews/EditCommentDialog.razor index b5635b51..0e0fdcf1 100644 --- a/src/iRLeagueManager.Web/Components/Reviews/EditCommentDialog.razor +++ b/src/iRLeagueManager.Web/Components/Reviews/EditCommentDialog.razor @@ -7,7 +7,7 @@ @inherits EditDialogBase @inject LeagueApiService ApiService - + diff --git a/src/iRLeagueManager.Web/Components/Reviews/EditReviewDialog.razor b/src/iRLeagueManager.Web/Components/Reviews/EditReviewDialog.razor index 27a42c63..9b398fc4 100644 --- a/src/iRLeagueManager.Web/Components/Reviews/EditReviewDialog.razor +++ b/src/iRLeagueManager.Web/Components/Reviews/EditReviewDialog.razor @@ -6,7 +6,7 @@ @using iRLeagueManager.Web.ViewModels @inherits EditDialogBase - + @@ -53,7 +53,7 @@ Cancel - Save + Save diff --git a/src/iRLeagueManager.Web/Components/Reviews/EditReviewResultDialog.razor b/src/iRLeagueManager.Web/Components/Reviews/EditReviewResultDialog.razor index 609e7a6b..b2bee6ec 100644 --- a/src/iRLeagueManager.Web/Components/Reviews/EditReviewResultDialog.razor +++ b/src/iRLeagueManager.Web/Components/Reviews/EditReviewResultDialog.razor @@ -7,7 +7,7 @@ @inherits EditDialogBase @inject LeagueApiService ApiService - + @@ -84,7 +84,7 @@ Cancel - Save + Save diff --git a/src/iRLeagueManager.Web/Data/LeagueApiService.cs b/src/iRLeagueManager.Web/Data/LeagueApiService.cs index 05ced6f7..33e96cd8 100644 --- a/src/iRLeagueManager.Web/Data/LeagueApiService.cs +++ b/src/iRLeagueManager.Web/Data/LeagueApiService.cs @@ -8,11 +8,8 @@ namespace iRLeagueManager.Web.Data; public sealed class LeagueApiService { - //private readonly ILogger logger; - public LeagueApiService(ILeagueApiClient apiClient, SharedStateService sharedState, ClientLocalTimeProvider localTimeProvider) { - //this.logger = logger; Client = apiClient; Shared = sharedState; ClientTimeProvider= localTimeProvider; diff --git a/src/iRLeagueManager.Web/Data/LeeagueModel.cs b/src/iRLeagueManager.Web/Data/LeeagueModel.cs deleted file mode 100644 index f576a63b..00000000 --- a/src/iRLeagueManager.Web/Data/LeeagueModel.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace iRLeagueManager.Web.Data; - -internal class LeeagueModel -{ -} \ No newline at end of file diff --git a/src/iRLeagueManager.Web/Pages/Schedules.razor b/src/iRLeagueManager.Web/Pages/Schedules.razor index 0565a0d5..11b4b822 100644 --- a/src/iRLeagueManager.Web/Pages/Schedules.razor +++ b/src/iRLeagueManager.Web/Pages/Schedules.razor @@ -7,7 +7,6 @@ @using iRLeagueManager.Web.Components @inherits LeagueComponentBase @inject SchedulesPageViewModel vm -@inject JsonSerializerOptions jsonOptions Schedules - @LeagueName diff --git a/src/iRLeagueManager.Web/Program.cs b/src/iRLeagueManager.Web/Program.cs index 719ca8e7..b28e9696 100644 --- a/src/iRLeagueManager.Web/Program.cs +++ b/src/iRLeagueManager.Web/Program.cs @@ -1,13 +1,10 @@ using Blazored.LocalStorage; -using iRLeagueApiCore.Common.Converters; using iRLeagueManager.Web; using iRLeagueManager.Web.Data; using iRLeagueManager.Web.Shared; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.AspNetCore.Components.Server; using Microsoft.AspNetCore.HttpOverrides; -using System.Text.Json; -using System.Text.Json.Serialization; using System.Reflection; using Microsoft.AspNetCore.Authorization; using MudBlazor.Services; @@ -30,14 +27,6 @@ builder.Services.AddMvvm(); builder.Services.AddLeagueApiService(); -//builder.Services.AddScoped(configure => -//{ -// var jsonOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); -// jsonOptions.Converters.Add(new JsonStringEnumConverter()); -// jsonOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; -// return jsonOptions; -//}); - builder.Services.AddLeagueApiClient(config => config .UseBaseAddress(builder.Configuration["APIServer"] ?? string.Empty) .UseTokenStore()); From baac749dfab5b56aaa59405b5dd623979e26a3ae Mon Sep 17 00:00:00 2001 From: Simon Schulze Date: Fri, 12 Jul 2024 16:36:56 +0200 Subject: [PATCH 6/7] bump version to 0.12.0 - update packages --- src/iRLeagueManager.Web/iRLeagueManager.Web.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj b/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj index c95100ca..0b5390bd 100644 --- a/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj +++ b/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj @@ -2,7 +2,7 @@ net7.0 - 0.11.11 + 0.12.0 enable enable aspnet-iRLeagueManager.Web-2B05F9DC-55A3-49D1-BD64-31507000EDF3 @@ -33,8 +33,8 @@ - - + + From 010b62116649983dbebe4a0dee9354b67a7bcbc8 Mon Sep 17 00:00:00 2001 From: Simon Schulze Date: Fri, 12 Jul 2024 16:39:28 +0200 Subject: [PATCH 7/7] remove some warnings --- src/iRLeagueManager.Web/Components/InputMarkdown.razor | 2 -- .../Components/Settings/Dialogs/PointSettingsDialog.razor | 2 -- src/iRLeagueManager.Web/Pages/Settings/LeagueSettings.razor | 2 +- src/iRLeagueManager.Web/Pages/Settings/ReviewSettings.razor | 2 +- src/iRLeagueManager.Web/Pages/Settings/Templates.razor.cs | 2 +- 5 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/iRLeagueManager.Web/Components/InputMarkdown.razor b/src/iRLeagueManager.Web/Components/InputMarkdown.razor index ebe1c5eb..ccbd37e4 100644 --- a/src/iRLeagueManager.Web/Components/InputMarkdown.razor +++ b/src/iRLeagueManager.Web/Components/InputMarkdown.razor @@ -21,8 +21,6 @@ @code { - private string uuid = "1"; - protected override bool TryParseValueFromString(string? value, [MaybeNullWhen(false)] out string result, [NotNullWhen(false)] out string? validationErrorMessage) { validationErrorMessage = null; diff --git a/src/iRLeagueManager.Web/Components/Settings/Dialogs/PointSettingsDialog.razor b/src/iRLeagueManager.Web/Components/Settings/Dialogs/PointSettingsDialog.razor index 51672489..ddc21e81 100644 --- a/src/iRLeagueManager.Web/Components/Settings/Dialogs/PointSettingsDialog.razor +++ b/src/iRLeagueManager.Web/Components/Settings/Dialogs/PointSettingsDialog.razor @@ -142,8 +142,6 @@ } } - private bool formulaHelpOpen = false; - protected override void OnParametersSet() { base.OnParametersSet(); diff --git a/src/iRLeagueManager.Web/Pages/Settings/LeagueSettings.razor b/src/iRLeagueManager.Web/Pages/Settings/LeagueSettings.razor index d7871867..4d5208f5 100644 --- a/src/iRLeagueManager.Web/Pages/Settings/LeagueSettings.razor +++ b/src/iRLeagueManager.Web/Pages/Settings/LeagueSettings.razor @@ -95,7 +95,7 @@ private bool showLeagueHiddenAlert = true; private bool seasonsExpanded = false; - private bool Loading => Bind(League, x => x.Loading); + private new bool Loading => Bind(League, x => x.Loading); private StatusResultValidator? ResultValidator { get; set; } diff --git a/src/iRLeagueManager.Web/Pages/Settings/ReviewSettings.razor b/src/iRLeagueManager.Web/Pages/Settings/ReviewSettings.razor index 50156f74..f74fc0de 100644 --- a/src/iRLeagueManager.Web/Pages/Settings/ReviewSettings.razor +++ b/src/iRLeagueManager.Web/Pages/Settings/ReviewSettings.razor @@ -69,7 +69,7 @@ @code { - private bool Loading => Bind(League, x => x.Loading) || Bind(Reviews, x => x.Loading); + private new bool Loading => Bind(League, x => x.Loading) || Bind(Reviews, x => x.Loading); private bool categoriesExpanded = false; diff --git a/src/iRLeagueManager.Web/Pages/Settings/Templates.razor.cs b/src/iRLeagueManager.Web/Pages/Settings/Templates.razor.cs index c9de3207..b2e8519d 100644 --- a/src/iRLeagueManager.Web/Pages/Settings/Templates.razor.cs +++ b/src/iRLeagueManager.Web/Pages/Settings/Templates.razor.cs @@ -19,7 +19,7 @@ public partial class Templates : LeagueComponentBase private string Status { get; set; } = string.Empty; private string Message { get; set; } = string.Empty; private IEnumerable Errors { get; set; } = Array.Empty(); - private bool Loading { get; set; } = false; + private new bool Loading { get; set; } = false; private enum TemplateType {