Refactor Blazor components to use code-behind files
- Move @code blocks from Exercises.razor, Home.razor, and Routines.razor to separate .cs files - Add XML documentation comments to all methods in the code-behind files
This commit is contained in:
@@ -65,102 +65,3 @@
|
|||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
|
||||||
[Parameter]
|
|
||||||
public string? UserId { get; set; }
|
|
||||||
|
|
||||||
private List<ExerciseDto> 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<bool>("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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
159
src/ASTRAIN.Client/Pages/Exercises.razor.cs
Normal file
159
src/ASTRAIN.Client/Pages/Exercises.razor.cs
Normal file
@@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Optional user id from route.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public string? UserId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The list of exercises for the current user.
|
||||||
|
/// </summary>
|
||||||
|
private List<ExerciseDto> ExerciseList { get; set; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the page is currently loading data.
|
||||||
|
/// </summary>
|
||||||
|
private bool IsLoading { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the create exercise UI is visible.
|
||||||
|
/// </summary>
|
||||||
|
private bool ShowCreateExercise { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name for a new exercise being created.
|
||||||
|
/// </summary>
|
||||||
|
private string NewExerciseName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The currently edited exercise id, if any.
|
||||||
|
/// </summary>
|
||||||
|
private int? EditingId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current edited exercise name.
|
||||||
|
/// </summary>
|
||||||
|
private string EditingName { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads exercises from the API.
|
||||||
|
/// </summary>
|
||||||
|
private async Task LoadExercisesAsync()
|
||||||
|
{
|
||||||
|
IsLoading = true;
|
||||||
|
ExerciseList = await Api.GetExercisesAsync(UserContext.UserId);
|
||||||
|
IsLoading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new exercise with the provided name.
|
||||||
|
/// </summary>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggles the create form visibility.
|
||||||
|
/// </summary>
|
||||||
|
private void ToggleCreate()
|
||||||
|
{
|
||||||
|
ShowCreateExercise = !ShowCreateExercise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Begin editing the supplied exercise.
|
||||||
|
/// </summary>
|
||||||
|
private void StartEdit(ExerciseDto exercise)
|
||||||
|
{
|
||||||
|
EditingId = exercise.Id;
|
||||||
|
EditingName = exercise.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel the current edit.
|
||||||
|
/// </summary>
|
||||||
|
private void CancelEdit()
|
||||||
|
{
|
||||||
|
EditingId = null;
|
||||||
|
EditingName = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save the edited exercise name.
|
||||||
|
/// </summary>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes the exercise with the given id after confirmation.
|
||||||
|
/// </summary>
|
||||||
|
private async Task DeleteExerciseAsync(int exerciseId)
|
||||||
|
{
|
||||||
|
var confirmed = await JS.InvokeAsync<bool>("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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,23 +14,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
31
src/ASTRAIN.Client/Pages/Home.razor.cs
Normal file
31
src/ASTRAIN.Client/Pages/Home.razor.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace ASTRAIN.Client.Pages;
|
||||||
|
|
||||||
|
public partial class Home
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Optional user id from route.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public string? UserId { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -129,188 +129,3 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
|
||||||
[Parameter]
|
|
||||||
public string? UserId { get; set; }
|
|
||||||
|
|
||||||
private List<ExerciseDto> ExerciseList { get; set; } = new();
|
|
||||||
private List<RoutineDto> RoutineList { get; set; } = new();
|
|
||||||
private bool IsLoading { get; set; } = true;
|
|
||||||
private bool ShowCreateRoutine { get; set; }
|
|
||||||
|
|
||||||
private string NewRoutineName { get; set; } = string.Empty;
|
|
||||||
private HashSet<int> SelectedExerciseIds { get; set; } = new();
|
|
||||||
|
|
||||||
private RoutineDto? EditingRoutine { get; set; }
|
|
||||||
private string EditingName { get; set; } = string.Empty;
|
|
||||||
private HashSet<int> EditingExerciseIds { get; set; } = new();
|
|
||||||
|
|
||||||
private RoutineDto? ActiveRun { get; set; }
|
|
||||||
private List<RoutineRunEntryDto> 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<bool>("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<bool>("confirm", "Are you sure you want to abort this routine run?");
|
|
||||||
if (!confirmed) return;
|
|
||||||
|
|
||||||
ActiveRun = null;
|
|
||||||
RunEntries = new List<RoutineRunEntryDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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<RoutineRunEntryDto>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
261
src/ASTRAIN.Client/Pages/Routines.razor.cs
Normal file
261
src/ASTRAIN.Client/Pages/Routines.razor.cs
Normal file
@@ -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
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Optional user id from route.
|
||||||
|
/// </summary>
|
||||||
|
[Parameter]
|
||||||
|
public string? UserId { get; set; }
|
||||||
|
|
||||||
|
private List<ExerciseDto> ExerciseList { get; set; } = new();
|
||||||
|
private List<RoutineDto> RoutineList { get; set; } = new();
|
||||||
|
private bool IsLoading { get; set; } = true;
|
||||||
|
private bool ShowCreateRoutine { get; set; }
|
||||||
|
|
||||||
|
private string NewRoutineName { get; set; } = string.Empty;
|
||||||
|
private HashSet<int> SelectedExerciseIds { get; set; } = new();
|
||||||
|
|
||||||
|
private RoutineDto? EditingRoutine { get; set; }
|
||||||
|
private string EditingName { get; set; } = string.Empty;
|
||||||
|
private HashSet<int> EditingExerciseIds { get; set; } = new();
|
||||||
|
|
||||||
|
private RoutineDto? ActiveRun { get; set; }
|
||||||
|
private List<RoutineRunEntryDto> RunEntries { get; set; } = new();
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads exercises and routines from the API and updates the UI state.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
private void ToggleExercise(int exerciseId)
|
||||||
|
{
|
||||||
|
if (!SelectedExerciseIds.Add(exerciseId))
|
||||||
|
{
|
||||||
|
SelectedExerciseIds.Remove(exerciseId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggles whether an exercise is selected when creating a routine.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new routine with the selected exercises.
|
||||||
|
/// </summary>
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleCreate()
|
||||||
|
{
|
||||||
|
ShowCreateRoutine = !ShowCreateRoutine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggle visibility of the create-routine UI.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
private void GoToExercises()
|
||||||
|
{
|
||||||
|
Navigation.NavigateTo($"/{UserContext.UserId}/exercises");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Navigate to the exercises page for the current user.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
private void StartEdit(RoutineDto routine)
|
||||||
|
{
|
||||||
|
EditingRoutine = routine;
|
||||||
|
EditingName = routine.Name;
|
||||||
|
EditingExerciseIds = routine.Exercises.Select(e => e.ExerciseId).ToHashSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Begin editing the supplied routine.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
private void CancelEdit()
|
||||||
|
{
|
||||||
|
EditingRoutine = null;
|
||||||
|
EditingName = string.Empty;
|
||||||
|
EditingExerciseIds.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel the current routine edit and reset state.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
private void ToggleEditExercise(int exerciseId)
|
||||||
|
{
|
||||||
|
if (!EditingExerciseIds.Add(exerciseId))
|
||||||
|
{
|
||||||
|
EditingExerciseIds.Remove(exerciseId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggle whether an exercise is selected in the routine edit UI.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save changes made to the currently edited routine.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
private async Task DeleteRoutineAsync(int routineId)
|
||||||
|
{
|
||||||
|
var confirmed = await JS.InvokeAsync<bool>("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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Delete the routine with the given id after confirmation.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start a routine run and prepare run entries.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
private void ToggleRunCompleted(int exerciseId)
|
||||||
|
{
|
||||||
|
var entry = RunEntries.FirstOrDefault(e => e.ExerciseId == exerciseId);
|
||||||
|
if (entry is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.Completed = !entry.Completed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Toggle the completion state of a run entry.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
private string GetExerciseName(int exerciseId)
|
||||||
|
{
|
||||||
|
return ExerciseList.FirstOrDefault(e => e.Id == exerciseId)?.Name ?? "Exercise";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the display name for an exercise id.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
private async Task AbortRun()
|
||||||
|
{
|
||||||
|
var confirmed = await JS.InvokeAsync<bool>("confirm", "Are you sure you want to abort this routine run?");
|
||||||
|
if (!confirmed) return;
|
||||||
|
|
||||||
|
ActiveRun = null;
|
||||||
|
RunEntries = new List<RoutineRunEntryDto>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Abort the active routine run after confirmation.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
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<RoutineRunEntryDto>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save the current routine run to the API.
|
||||||
|
/// </summary>
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user