diff --git a/src/ASTRAIN.Client/Pages/Exercises.razor b/src/ASTRAIN.Client/Pages/Exercises.razor index a503992..d179989 100644 --- a/src/ASTRAIN.Client/Pages/Exercises.razor +++ b/src/ASTRAIN.Client/Pages/Exercises.razor @@ -65,102 +65,3 @@ -@code { - [Parameter] - public string? UserId { get; set; } - - private List ExerciseList { get; set; } = new(); - private bool IsLoading { get; set; } = true; - private bool ShowCreateExercise { get; set; } - private string NewExerciseName { get; set; } = string.Empty; - private int? EditingId { get; set; } - private string EditingName { get; set; } = string.Empty; - - protected override async Task OnInitializedAsync() - { - var ensured = await Api.EnsureUserAsync(UserId); - if (string.IsNullOrWhiteSpace(ensured)) - { - return; - } - - UserContext.SetUserId(ensured); - if (UserId != ensured) - { - Navigation.NavigateTo($"/{ensured}/exercises", true); - return; - } - - await LoadExercisesAsync(); - } - - private async Task LoadExercisesAsync() - { - IsLoading = true; - ExerciseList = await Api.GetExercisesAsync(UserContext.UserId); - IsLoading = false; - } - - private async Task CreateExerciseAsync() - { - if (string.IsNullOrWhiteSpace(NewExerciseName)) - { - return; - } - - var result = await Api.CreateExerciseAsync(UserContext.UserId, new ExerciseUpsertRequest(NewExerciseName)); - if (result is not null) - { - ExerciseList.Add(result); - ExerciseList = ExerciseList.OrderBy(e => e.Name).ToList(); - NewExerciseName = string.Empty; - } - } - - private void ToggleCreate() - { - ShowCreateExercise = !ShowCreateExercise; - } - - private void StartEdit(ExerciseDto exercise) - { - EditingId = exercise.Id; - EditingName = exercise.Name; - } - - private void CancelEdit() - { - EditingId = null; - EditingName = string.Empty; - } - - private async Task SaveEditAsync(int exerciseId) - { - if (string.IsNullOrWhiteSpace(EditingName)) - { - return; - } - - var result = await Api.UpdateExerciseAsync(UserContext.UserId, exerciseId, new ExerciseUpsertRequest(EditingName)); - if (result is not null) - { - var index = ExerciseList.FindIndex(e => e.Id == exerciseId); - if (index >= 0) - { - ExerciseList[index] = result; - ExerciseList = ExerciseList.OrderBy(e => e.Name).ToList(); - } - } - - CancelEdit(); - } - - private async Task DeleteExerciseAsync(int exerciseId) - { - var confirmed = await JS.InvokeAsync("confirm", "Are you sure you want to delete this exercise?"); - if (!confirmed) return; - - await Api.DeleteExerciseAsync(UserContext.UserId, exerciseId); - ExerciseList.RemoveAll(e => e.Id == exerciseId); - } -} diff --git a/src/ASTRAIN.Client/Pages/Exercises.razor.cs b/src/ASTRAIN.Client/Pages/Exercises.razor.cs new file mode 100644 index 0000000..c6ca261 --- /dev/null +++ b/src/ASTRAIN.Client/Pages/Exercises.razor.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using ASTRAIN.Shared.Dtos; +using ASTRAIN.Shared.Requests; + +namespace ASTRAIN.Client.Pages; + +public partial class Exercises +{ + /// + /// Optional user id from route. + /// + [Parameter] + public string? UserId { get; set; } + + /// + /// The list of exercises for the current user. + /// + private List ExerciseList { get; set; } = new(); + + /// + /// Whether the page is currently loading data. + /// + private bool IsLoading { get; set; } = true; + + /// + /// Whether the create exercise UI is visible. + /// + private bool ShowCreateExercise { get; set; } + + /// + /// Name for a new exercise being created. + /// + private string NewExerciseName { get; set; } = string.Empty; + + /// + /// The currently edited exercise id, if any. + /// + private int? EditingId { get; set; } + + /// + /// The current edited exercise name. + /// + private string EditingName { get; set; } = string.Empty; + + /// + protected override async Task OnInitializedAsync() + { + var ensured = await Api.EnsureUserAsync(UserId); + if (string.IsNullOrWhiteSpace(ensured)) + { + return; + } + + UserContext.SetUserId(ensured); + if (UserId != ensured) + { + Navigation.NavigateTo($"/{ensured}/exercises", true); + return; + } + + await LoadExercisesAsync(); + } + + /// + /// Loads exercises from the API. + /// + private async Task LoadExercisesAsync() + { + IsLoading = true; + ExerciseList = await Api.GetExercisesAsync(UserContext.UserId); + IsLoading = false; + } + + /// + /// Creates a new exercise with the provided name. + /// + private async Task CreateExerciseAsync() + { + if (string.IsNullOrWhiteSpace(NewExerciseName)) + { + return; + } + + var result = await Api.CreateExerciseAsync(UserContext.UserId, new ExerciseUpsertRequest(NewExerciseName)); + if (result is not null) + { + ExerciseList.Add(result); + ExerciseList = ExerciseList.OrderBy(e => e.Name).ToList(); + NewExerciseName = string.Empty; + } + } + + /// + /// Toggles the create form visibility. + /// + private void ToggleCreate() + { + ShowCreateExercise = !ShowCreateExercise; + } + + /// + /// Begin editing the supplied exercise. + /// + private void StartEdit(ExerciseDto exercise) + { + EditingId = exercise.Id; + EditingName = exercise.Name; + } + + /// + /// Cancel the current edit. + /// + private void CancelEdit() + { + EditingId = null; + EditingName = string.Empty; + } + + /// + /// Save the edited exercise name. + /// + private async Task SaveEditAsync(int exerciseId) + { + if (string.IsNullOrWhiteSpace(EditingName)) + { + return; + } + + var result = await Api.UpdateExerciseAsync(UserContext.UserId, exerciseId, new ExerciseUpsertRequest(EditingName)); + if (result is not null) + { + var index = ExerciseList.FindIndex(e => e.Id == exerciseId); + if (index >= 0) + { + ExerciseList[index] = result; + ExerciseList = ExerciseList.OrderBy(e => e.Name).ToList(); + } + } + + CancelEdit(); + } + + /// + /// Deletes the exercise with the given id after confirmation. + /// + private async Task DeleteExerciseAsync(int exerciseId) + { + var confirmed = await JS.InvokeAsync("confirm", "Are you sure you want to delete this exercise?"); + if (!confirmed) return; + + await Api.DeleteExerciseAsync(UserContext.UserId, exerciseId); + ExerciseList.RemoveAll(e => e.Id == exerciseId); + } +} diff --git a/src/ASTRAIN.Client/Pages/Home.razor b/src/ASTRAIN.Client/Pages/Home.razor index dedda39..7b296a8 100644 --- a/src/ASTRAIN.Client/Pages/Home.razor +++ b/src/ASTRAIN.Client/Pages/Home.razor @@ -14,23 +14,3 @@ -@code { - [Parameter] - public string? UserId { get; set; } - - protected override async Task OnInitializedAsync() - { - var ensured = await Api.EnsureUserAsync(UserId); - if (string.IsNullOrWhiteSpace(ensured)) - { - return; - } - - UserContext.SetUserId(ensured); - var target = $"/{ensured}/routines"; - if (!Navigation.Uri.EndsWith(target, StringComparison.OrdinalIgnoreCase)) - { - Navigation.NavigateTo(target, true); - } - } -} diff --git a/src/ASTRAIN.Client/Pages/Home.razor.cs b/src/ASTRAIN.Client/Pages/Home.razor.cs new file mode 100644 index 0000000..1bef76f --- /dev/null +++ b/src/ASTRAIN.Client/Pages/Home.razor.cs @@ -0,0 +1,31 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; + +namespace ASTRAIN.Client.Pages; + +public partial class Home +{ + /// + /// Optional user id from route. + /// + [Parameter] + public string? UserId { get; set; } + + /// + protected override async Task OnInitializedAsync() + { + var ensured = await Api.EnsureUserAsync(UserId); + if (string.IsNullOrWhiteSpace(ensured)) + { + return; + } + + UserContext.SetUserId(ensured); + var target = $"/{ensured}/routines"; + if (!Navigation.Uri.EndsWith(target, StringComparison.OrdinalIgnoreCase)) + { + Navigation.NavigateTo(target, true); + } + } +} diff --git a/src/ASTRAIN.Client/Pages/Routines.razor b/src/ASTRAIN.Client/Pages/Routines.razor index defefda..c5adbca 100644 --- a/src/ASTRAIN.Client/Pages/Routines.razor +++ b/src/ASTRAIN.Client/Pages/Routines.razor @@ -129,188 +129,3 @@ } -@code { - [Parameter] - public string? UserId { get; set; } - - private List ExerciseList { get; set; } = new(); - private List RoutineList { get; set; } = new(); - private bool IsLoading { get; set; } = true; - private bool ShowCreateRoutine { get; set; } - - private string NewRoutineName { get; set; } = string.Empty; - private HashSet SelectedExerciseIds { get; set; } = new(); - - private RoutineDto? EditingRoutine { get; set; } - private string EditingName { get; set; } = string.Empty; - private HashSet EditingExerciseIds { get; set; } = new(); - - private RoutineDto? ActiveRun { get; set; } - private List RunEntries { get; set; } = new(); - - protected override async Task OnInitializedAsync() - { - var ensured = await Api.EnsureUserAsync(UserId); - if (string.IsNullOrWhiteSpace(ensured)) - { - return; - } - - UserContext.SetUserId(ensured); - if (UserId != ensured) - { - Navigation.NavigateTo($"/{ensured}/routines", true); - return; - } - - await LoadDataAsync(); - } - - private async Task LoadDataAsync() - { - IsLoading = true; - ExerciseList = await Api.GetExercisesAsync(UserContext.UserId); - RoutineList = await Api.GetRoutinesAsync(UserContext.UserId); - IsLoading = false; - } - - private void ToggleExercise(int exerciseId) - { - if (!SelectedExerciseIds.Add(exerciseId)) - { - SelectedExerciseIds.Remove(exerciseId); - } - } - - private async Task CreateRoutineAsync() - { - if (string.IsNullOrWhiteSpace(NewRoutineName)) - { - return; - } - - var request = new RoutineUpsertRequest(NewRoutineName, SelectedExerciseIds.ToList()); - var created = await Api.CreateRoutineAsync(UserContext.UserId, request); - if (created is not null) - { - RoutineList.Add(created); - RoutineList = RoutineList.OrderBy(r => r.Name).ToList(); - NewRoutineName = string.Empty; - SelectedExerciseIds.Clear(); - } - } - - private void ToggleCreate() - { - ShowCreateRoutine = !ShowCreateRoutine; - } - - private void GoToExercises() - { - Navigation.NavigateTo($"/{UserContext.UserId}/exercises"); - } - - private void StartEdit(RoutineDto routine) - { - EditingRoutine = routine; - EditingName = routine.Name; - EditingExerciseIds = routine.Exercises.Select(e => e.ExerciseId).ToHashSet(); - } - - private void CancelEdit() - { - EditingRoutine = null; - EditingName = string.Empty; - EditingExerciseIds.Clear(); - } - - private void ToggleEditExercise(int exerciseId) - { - if (!EditingExerciseIds.Add(exerciseId)) - { - EditingExerciseIds.Remove(exerciseId); - } - } - - private async Task SaveEditAsync() - { - if (EditingRoutine is null) - { - return; - } - - var request = new RoutineUpsertRequest(EditingName, EditingExerciseIds.ToList()); - var updated = await Api.UpdateRoutineAsync(UserContext.UserId, EditingRoutine.Id, request); - if (updated is not null) - { - var index = RoutineList.FindIndex(r => r.Id == EditingRoutine.Id); - if (index >= 0) - { - RoutineList[index] = updated; - RoutineList = RoutineList.OrderBy(r => r.Name).ToList(); - } - } - - CancelEdit(); - } - - private async Task DeleteRoutineAsync(int routineId) - { - var confirmed = await JS.InvokeAsync("confirm", "Are you sure you want to delete this routine?"); - if (!confirmed) return; - - await Api.DeleteRoutineAsync(UserContext.UserId, routineId); - RoutineList.RemoveAll(r => r.Id == routineId); - } - - private async Task StartRun(RoutineDto routine) - { - ActiveRun = routine; - var lastRun = await Api.GetLastRunAsync(UserContext.UserId, routine.Id); - RunEntries = routine.Exercises - .OrderBy(e => e.Order) - .Select(e => - { - var last = lastRun.Entries.FirstOrDefault(x => x.ExerciseId == e.ExerciseId); - return new RoutineRunEntryDto(e.ExerciseId, last?.Weight ?? 0, false); - }).ToList(); - } - - private void ToggleRunCompleted(int exerciseId) - { - var entry = RunEntries.FirstOrDefault(e => e.ExerciseId == exerciseId); - if (entry is null) - { - return; - } - - entry.Completed = !entry.Completed; - } - - private string GetExerciseName(int exerciseId) - { - return ExerciseList.FirstOrDefault(e => e.Id == exerciseId)?.Name ?? "Exercise"; - } - - private async Task AbortRun() - { - var confirmed = await JS.InvokeAsync("confirm", "Are you sure you want to abort this routine run?"); - if (!confirmed) return; - - ActiveRun = null; - RunEntries = new List(); - } - - private async Task SaveRunAsync() - { - if (ActiveRun is null) - { - return; - } - - var request = new RoutineRunRequest(RunEntries); - await Api.SaveRunAsync(UserContext.UserId, ActiveRun.Id, request); - ActiveRun = null; - RunEntries = new List(); - } -} diff --git a/src/ASTRAIN.Client/Pages/Routines.razor.cs b/src/ASTRAIN.Client/Pages/Routines.razor.cs new file mode 100644 index 0000000..4cd8432 --- /dev/null +++ b/src/ASTRAIN.Client/Pages/Routines.razor.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using ASTRAIN.Shared.Dtos; +using ASTRAIN.Shared.Requests; + +namespace ASTRAIN.Client.Pages; + +public partial class Routines +{ + /// + /// Optional user id from route. + /// + [Parameter] + public string? UserId { get; set; } + + private List ExerciseList { get; set; } = new(); + private List RoutineList { get; set; } = new(); + private bool IsLoading { get; set; } = true; + private bool ShowCreateRoutine { get; set; } + + private string NewRoutineName { get; set; } = string.Empty; + private HashSet SelectedExerciseIds { get; set; } = new(); + + private RoutineDto? EditingRoutine { get; set; } + private string EditingName { get; set; } = string.Empty; + private HashSet EditingExerciseIds { get; set; } = new(); + + private RoutineDto? ActiveRun { get; set; } + private List RunEntries { get; set; } = new(); + + /// + protected override async Task OnInitializedAsync() + { + var ensured = await Api.EnsureUserAsync(UserId); + if (string.IsNullOrWhiteSpace(ensured)) + { + return; + } + + UserContext.SetUserId(ensured); + if (UserId != ensured) + { + Navigation.NavigateTo($"/{ensured}/routines", true); + return; + } + + await LoadDataAsync(); + } + + private async Task LoadDataAsync() + { + IsLoading = true; + ExerciseList = await Api.GetExercisesAsync(UserContext.UserId); + RoutineList = await Api.GetRoutinesAsync(UserContext.UserId); + IsLoading = false; + } + + /// + /// Loads exercises and routines from the API and updates the UI state. + /// + + private void ToggleExercise(int exerciseId) + { + if (!SelectedExerciseIds.Add(exerciseId)) + { + SelectedExerciseIds.Remove(exerciseId); + } + } + + /// + /// Toggles whether an exercise is selected when creating a routine. + /// + + private async Task CreateRoutineAsync() + { + if (string.IsNullOrWhiteSpace(NewRoutineName)) + { + return; + } + + var request = new RoutineUpsertRequest(NewRoutineName, SelectedExerciseIds.ToList()); + var created = await Api.CreateRoutineAsync(UserContext.UserId, request); + if (created is not null) + { + RoutineList.Add(created); + RoutineList = RoutineList.OrderBy(r => r.Name).ToList(); + NewRoutineName = string.Empty; + SelectedExerciseIds.Clear(); + } + + /// + /// Creates a new routine with the selected exercises. + /// + } + + private void ToggleCreate() + { + ShowCreateRoutine = !ShowCreateRoutine; + } + + /// + /// Toggle visibility of the create-routine UI. + /// + + private void GoToExercises() + { + Navigation.NavigateTo($"/{UserContext.UserId}/exercises"); + } + + /// + /// Navigate to the exercises page for the current user. + /// + + private void StartEdit(RoutineDto routine) + { + EditingRoutine = routine; + EditingName = routine.Name; + EditingExerciseIds = routine.Exercises.Select(e => e.ExerciseId).ToHashSet(); + } + + /// + /// Begin editing the supplied routine. + /// + + private void CancelEdit() + { + EditingRoutine = null; + EditingName = string.Empty; + EditingExerciseIds.Clear(); + } + + /// + /// Cancel the current routine edit and reset state. + /// + + private void ToggleEditExercise(int exerciseId) + { + if (!EditingExerciseIds.Add(exerciseId)) + { + EditingExerciseIds.Remove(exerciseId); + } + } + + /// + /// Toggle whether an exercise is selected in the routine edit UI. + /// + + private async Task SaveEditAsync() + { + if (EditingRoutine is null) + { + return; + } + + var request = new RoutineUpsertRequest(EditingName, EditingExerciseIds.ToList()); + var updated = await Api.UpdateRoutineAsync(UserContext.UserId, EditingRoutine.Id, request); + if (updated is not null) + { + var index = RoutineList.FindIndex(r => r.Id == EditingRoutine.Id); + if (index >= 0) + { + RoutineList[index] = updated; + RoutineList = RoutineList.OrderBy(r => r.Name).ToList(); + } + } + + CancelEdit(); + } + + /// + /// Save changes made to the currently edited routine. + /// + + private async Task DeleteRoutineAsync(int routineId) + { + var confirmed = await JS.InvokeAsync("confirm", "Are you sure you want to delete this routine?"); + if (!confirmed) return; + + await Api.DeleteRoutineAsync(UserContext.UserId, routineId); + RoutineList.RemoveAll(r => r.Id == routineId); + } + + /// + /// Delete the routine with the given id after confirmation. + /// + + private async Task StartRun(RoutineDto routine) + { + ActiveRun = routine; + var lastRun = await Api.GetLastRunAsync(UserContext.UserId, routine.Id); + RunEntries = routine.Exercises + .OrderBy(e => e.Order) + .Select(e => + { + var last = lastRun.Entries.FirstOrDefault(x => x.ExerciseId == e.ExerciseId); + return new RoutineRunEntryDto(e.ExerciseId, last?.Weight ?? 0, false); + }).ToList(); + } + + /// + /// Start a routine run and prepare run entries. + /// + + private void ToggleRunCompleted(int exerciseId) + { + var entry = RunEntries.FirstOrDefault(e => e.ExerciseId == exerciseId); + if (entry is null) + { + return; + } + + entry.Completed = !entry.Completed; + } + + /// + /// Toggle the completion state of a run entry. + /// + + private string GetExerciseName(int exerciseId) + { + return ExerciseList.FirstOrDefault(e => e.Id == exerciseId)?.Name ?? "Exercise"; + } + + /// + /// Get the display name for an exercise id. + /// + + private async Task AbortRun() + { + var confirmed = await JS.InvokeAsync("confirm", "Are you sure you want to abort this routine run?"); + if (!confirmed) return; + + ActiveRun = null; + RunEntries = new List(); + } + + /// + /// Abort the active routine run after confirmation. + /// + + private async Task SaveRunAsync() + { + if (ActiveRun is null) + { + return; + } + + var request = new RoutineRunRequest(RunEntries); + await Api.SaveRunAsync(UserContext.UserId, ActiveRun.Id, request); + ActiveRun = null; + RunEntries = new List(); + } + + /// + /// Save the current routine run to the API. + /// +}