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/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/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/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/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/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/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..e0e0ac21 --- /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..4f5a5a55 --- /dev/null +++ b/src/iRLeagueManager.Web/Components/Standings/RaceByRacePoints.razor.css @@ -0,0 +1,23 @@ +.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%); +} + +.mud-simple-table .mud-table-container table tbody tr td.dropped { + color: var(--mud-palette-text-disabled); +} \ No newline at end of file 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..33e96cd8 100644 --- a/src/iRLeagueManager.Web/Data/LeagueApiService.cs +++ b/src/iRLeagueManager.Web/Data/LeagueApiService.cs @@ -8,20 +8,15 @@ namespace iRLeagueManager.Web.Data; 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/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/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 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/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/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 { 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/Program.cs b/src/iRLeagueManager.Web/Program.cs index 26d5d6ef..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,15 +27,6 @@ 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.AddLeagueApiClient(config => config .UseBaseAddress(builder.Configuration["APIServer"] ?? string.Empty) .UseTokenStore()); 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 5e42610b..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 @@ - - + +