diff --git a/ExerciseTracker.AnaClos/ExerciseTracker.AnaClos.sln b/ExerciseTracker.AnaClos/ExerciseTracker.AnaClos.sln new file mode 100644 index 00000000..cee3cb19 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker.AnaClos.sln @@ -0,0 +1,30 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExerciseTracker", "ExerciseTracker\ExerciseTracker.csproj", "{D9168DBD-6026-4631-A708-5E61E31D06F8}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Elementos de la solución", "Elementos de la solución", "{34D32A39-5006-4278-AC54-C6B97F7F5C31}" + ProjectSection(SolutionItems) = preProject + Readme.txt = Readme.txt + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D9168DBD-6026-4631-A708-5E61E31D06F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D9168DBD-6026-4631-A708-5E61E31D06F8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D9168DBD-6026-4631-A708-5E61E31D06F8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D9168DBD-6026-4631-A708-5E61E31D06F8}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {90F22CA4-8D08-4E1D-A45C-0C4ACCC61F8D} + EndGlobalSection +EndGlobal diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Controllers/ExerciseController.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Controllers/ExerciseController.cs new file mode 100644 index 00000000..c89dec50 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Controllers/ExerciseController.cs @@ -0,0 +1,294 @@ +using ExerciseTracker.DTO; +using ExerciseTracker.Models; +using ExerciseTracker.Services; +using ExerciseTracker.UI; +using ExerciseTracker.Validators; + +namespace ExerciseTracker.Controllers; + +public class ExerciseController : IController +{ + private List mainOptions = new List { "Add", "Delete", "Update", "View", "Exit Menu" }; + private UserInput _userInput; + private IService _exerciseService; + public ExerciseController(UserInput userInput, IService exerciseService) + { + _userInput = userInput; + _exerciseService = exerciseService; + } + + public void Menu() + { + string option; + do + { + option = _userInput.Menu("Manage Exercises", "blue", mainOptions); + switch (option) + { + case "Add": + Add(); + break; + case "Delete": + Delete(); + break; + case "Update": + Update(); + break; + case "View": + View(); + break; + case "View All": + ViewAll(); + break; + } + } while (option != "Exit Menu"); + } + + public void Add() + { + string startString; + string endString; + DateTime startTime; + DateTime endTime; + + _userInput.ShowMessage("The new shift must be after the last shift interval. The shift interval must not exceed 8 hours. ", "blue"); + + do + { + startString = _userInput.GetString("Start Time in format yy/MM/dd HH:mm:ss"); + startTime = ExerciseValidator.DateTimeValidator(startString); + } while (startTime == DateTime.MinValue); + + do + { + endString = _userInput.GetString("End Time in format yy/MM/dd HH:mm:ss"); + endTime = ExerciseValidator.DateTimeValidator(endString); + } while (endTime == DateTime.MinValue); + + if (!ExerciseValidator.IntervalValidator(startTime, endTime)) + { + _userInput.MessageAndPressKey("The shift interval does not meet the requested requirements.", "red"); + return; + } + + var last10Exercises = _exerciseService.GetLast10(); + var lastExercise = last10Exercises.FirstOrDefault(); + + + if (lastExercise != null && !ExerciseValidator.OrderValidator(lastExercise, startTime)) + { + _userInput.MessageAndPressKey("The time slot is already used", "red"); + return; + } + + string comments = _userInput.GetString("Input a comment."); + + Exercise exercise = new Exercise + { + Id = 0, + DateStart = startTime, + DateEnd = endTime, + Duration = endTime - startTime, + Comments = comments + }; + try + { + _exerciseService.Add(exercise); + _userInput.MessageAndPressKey("Successfully created exercise.", "orange1"); + } + catch (Exception ex) + { + _userInput.MessageAndPressKey("The exercise could not be created", "orange1"); + } + } + + public void Delete() + { + bool confirmation = _userInput.Choice("You can only delete the last record, continue?"); + if (!confirmation) + { + return; + } + + var exercises = _exerciseService.GetLast10(); + Exercise exercise = exercises.FirstOrDefault(); + if (exercise == null) + { + _userInput.MessageAndPressKey("There is no exercise to delete", "red"); + return; + } + try + { + _exerciseService.Delete(exercise); + _userInput.MessageAndPressKey("Successfully deleted exercise.", "orange1"); + } + catch (Exception ex) + { + _userInput.MessageAndPressKey("The exercise couldn't be deleted", "red"); + } + } + + public void Update() + { + string startString; + DateTime startTime; + string endString; + DateTime endTime; + bool confirmation = _userInput.Choice("You can only update the last record, continue?"); + if (!confirmation) + { + return; + } + + var exercises = _exerciseService.GetLast10().ToList(); + Exercise exercise = exercises.FirstOrDefault(); + if (exercise == null) + { + _userInput.MessageAndPressKey("There is no exercise to update", "red"); + return; + } + + do + { + startString = _userInput.GetString("Start Time in format yy/MM/dd HH:mm:ss"); + startTime = ExerciseValidator.DateTimeValidator(startString); + } while (startTime == DateTime.MinValue); + + do + { + endString = _userInput.GetString("End Time in format yy/MM/dd HH:mm:ss"); + endTime = ExerciseValidator.DateTimeValidator(endString); + } while (endTime == DateTime.MinValue); + + if (!ExerciseValidator.IntervalValidator(startTime, endTime)) + { + _userInput.MessageAndPressKey("The shift interval does not meet the requested requirements.", "red"); + return; + } + + exercises.RemoveAt(0); + if (!ExerciseValidator.OrderValidator(exercises.FirstOrDefault(), startTime)) + { + _userInput.MessageAndPressKey("The time slot is already used", "red"); + } + + string comments = _userInput.GetString("Input a comment."); + exercise.DateStart = startTime; + exercise.DateEnd = endTime; + exercise.CalculateDuration(); + exercise.Comments = comments; + try + { + _exerciseService.Update(exercise); + _userInput.MessageAndPressKey("Successfully updated exercise.", "orange1"); + } + catch (Exception ex) + { + _userInput.MessageAndPressKey("The exercise couldn't be updated", "red"); + } + } + + public void View() + { + int order; + + var exercises = _exerciseService.GetLast10().ToList(); + if (exercises.Count == 0) + { + _userInput.MessageAndPressKey("There is no exercise to select ", "red"); + return; + } + + var orderedExercises = exercises.OrderBy(sh => sh.Id).ToList(); + List stringExercises = ExerciseToString(orderedExercises); + string stringExercise = GetExerciseFromMenu("Select a exercise to view details", stringExercises); + if (stringExercise == "Exit Menu") + { + return; + } + + int.TryParse(stringExercise.Split('#')[1], out order); + + string[] columns = { "Property", "Value" }; + + var exercise = orderedExercises.ElementAt(order - 1); + + var recordExercise = ExerciseToProperties(exercise); + + _userInput.ShowTable("Exercise", columns, recordExercise); + _userInput.PressKey("Press a key to continue."); + } + + public void ViewAll() + { + var exercises = _exerciseService.GetLast10().ToList(); + if (exercises.Count == 0) + { + _userInput.MessageAndPressKey("There is no exercises to view ", "red"); + return; + } + + foreach (Exercise exercise in exercises) + { + + exercise.CalculateDuration(); + _userInput.ShowMessage($"Exercise Date: {exercise.DateStart.Year}/{exercise.DateStart.Month}/{exercise.DateStart.Day} Duration: {exercise.Duration.Hours} hours, {exercise.Duration.Minutes} minutes, {exercise.Duration.Seconds} seconds", "green"); + } + + _userInput.PressKey("Press a key to continue."); + } + public List ExerciseToString(List exercises) + { + var tableRecord = new List(); + + for (int i = 1; i <= exercises.Count; i++) + { + tableRecord.Add($"Exercise #{i}"); + } + return tableRecord; + } + + public int GetOrderFromList(List stringShifts, string stringShift) + { + int order = 0; + for (int i = 0; i < stringShifts.Count; i++) + { + if (stringShifts[i] == stringShift) + { + order = i; + } + } + return order; + } + + public string GetExerciseFromMenu(string title, List stringShifts) + { + stringShifts.Add("Exit Menu"); + + string stringExercise = _userInput.Menu(title, "blue", stringShifts); + if (stringExercise == "Exit Menu") + { + return null; + } + return stringExercise; + } + + public List ExerciseToProperties(Exercise exercise) + { + var tableRecord = new List(); + RecordDto record = null; + foreach (var property in exercise.GetType().GetProperties()) + { + if (property.GetValue(exercise) != null) + { + string value = ""; + value = property.GetValue(exercise).ToString(); + + record = new RecordDto { Column1 = property.Name, Column2 = value }; + tableRecord.Add(record); + } + } + + return tableRecord; + } +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Controllers/IController.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Controllers/IController.cs new file mode 100644 index 00000000..ba6ac022 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Controllers/IController.cs @@ -0,0 +1,6 @@ +namespace ExerciseTracker.Controllers; + +public interface IController +{ + public void Menu(); +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/DTO/RecordDto.cs b/ExerciseTracker.AnaClos/ExerciseTracker/DTO/RecordDto.cs new file mode 100644 index 00000000..0b8a0be1 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/DTO/RecordDto.cs @@ -0,0 +1,7 @@ +namespace ExerciseTracker.DTO; + +public class RecordDto +{ + public string Column1 { get; set; } + public string Column2 { get; set; } +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Data/ExerciseDbContext.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Data/ExerciseDbContext.cs new file mode 100644 index 00000000..693c8981 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Data/ExerciseDbContext.cs @@ -0,0 +1,19 @@ +using Microsoft.EntityFrameworkCore; +using ExerciseTracker.Models; + +namespace ExerciseTracker.Data; + +public class ExerciseDbContext : DbContext +{ + public string _connectionString; + public ExerciseDbContext(DbContextOptions options) : base(options) + { + } + + public DbSet Exercises { get; set; } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity().ToTable("Exercise"); + } +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/ExerciseTracker.csproj b/ExerciseTracker.AnaClos/ExerciseTracker/ExerciseTracker.csproj new file mode 100644 index 00000000..80b061de --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/ExerciseTracker.csproj @@ -0,0 +1,30 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + Always + + + Always + + + + diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Migrations/20250215182738_Initial-create.Designer.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Migrations/20250215182738_Initial-create.Designer.cs new file mode 100644 index 00000000..c788e41c --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Migrations/20250215182738_Initial-create.Designer.cs @@ -0,0 +1,55 @@ +// +using System; +using ExerciseTracker.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ExerciseTracker.Migrations +{ + [DbContext(typeof(ExerciseDbContext))] + [Migration("20250215182738_Initial-create")] + partial class Initialcreate + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("ExerciseTracker.Models.Exercise", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comments") + .HasColumnType("nvarchar(max)"); + + b.Property("DateEnd") + .HasColumnType("datetime2"); + + b.Property("DateStart") + .HasColumnType("datetime2"); + + b.Property("Duration") + .HasColumnType("time"); + + b.HasKey("Id"); + + b.ToTable("Exercise", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Migrations/20250215182738_Initial-create.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Migrations/20250215182738_Initial-create.cs new file mode 100644 index 00000000..7c2321f3 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Migrations/20250215182738_Initial-create.cs @@ -0,0 +1,38 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace ExerciseTracker.Migrations +{ + /// + public partial class Initialcreate : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "Exercise", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + DateStart = table.Column(type: "datetime2", nullable: false), + DateEnd = table.Column(type: "datetime2", nullable: false), + Duration = table.Column(type: "time", nullable: false), + Comments = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_Exercise", x => x.Id); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "Exercise"); + } + } +} diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Migrations/ExerciseDbContextModelSnapshot.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Migrations/ExerciseDbContextModelSnapshot.cs new file mode 100644 index 00000000..7a84173c --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Migrations/ExerciseDbContextModelSnapshot.cs @@ -0,0 +1,52 @@ +// +using System; +using ExerciseTracker.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace ExerciseTracker.Migrations +{ + [DbContext(typeof(ExerciseDbContext))] + partial class ExerciseDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.1") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("ExerciseTracker.Models.Exercise", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Comments") + .HasColumnType("nvarchar(max)"); + + b.Property("DateEnd") + .HasColumnType("datetime2"); + + b.Property("DateStart") + .HasColumnType("datetime2"); + + b.Property("Duration") + .HasColumnType("time"); + + b.HasKey("Id"); + + b.ToTable("Exercise", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Models/Exercise.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Models/Exercise.cs new file mode 100644 index 00000000..e1ec49d6 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Models/Exercise.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace ExerciseTracker.Models; + +public class Exercise +{ + public int Id { get; set; } + [Required] + public DateTime DateStart { get; set; } + [Required] + public DateTime DateEnd { get; set; } + [Required] + public TimeSpan Duration { get; set; } + public string? Comments { get; set; } + + public void CalculateDuration() + { + Duration = DateEnd - DateStart; + } +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Program.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Program.cs new file mode 100644 index 00000000..9e0b8aee --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Program.cs @@ -0,0 +1,25 @@ +using ExerciseTracker.Controllers; +using ExerciseTracker.Data; +using ExerciseTracker.Repositories; +using ExerciseTracker.Services; +using ExerciseTracker.UI; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); +string connectionString = builder.Configuration.GetConnectionString("ExerciseTrackerConnection"); +builder.Services.AddDbContext(opt => opt.UseSqlServer(connectionString)); + +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddTransient(); +builder.Services.AddSingleton(); + +using IHost host = builder.Build(); + +var serviceProvider = host.Services; +var exerciseController = serviceProvider.GetRequiredService(); +exerciseController.Menu(); +host.Run(); \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Repositories/ExerciseRepository.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Repositories/ExerciseRepository.cs new file mode 100644 index 00000000..8d0b28d6 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Repositories/ExerciseRepository.cs @@ -0,0 +1,76 @@ +using ExerciseTracker.Data; +using ExerciseTracker.Models; + +namespace ExerciseTracker.Repositories; + +public class ExerciseRepository : IRepository +{ + private ExerciseDbContext _context; + public ExerciseRepository(ExerciseDbContext context) + { + _context = context; + } + + void IRepository.Add(Exercise exercise) + { + try + { + _context.Exercises.Add(exercise); + _context.SaveChanges(); + } + catch (Exception ex) + { + throw; + } + } + + void IRepository.Delete(Exercise exercise) + { + try + { + _context.Exercises.Remove(exercise); + _context.SaveChanges(); + } + catch (Exception ex) + { + throw; + } + } + + IEnumerable IRepository.GetAll() + { + try + { + return _context.Exercises.ToList(); + } + catch (Exception ex) + { + return null; + } + } + + Exercise IRepository.GetById(int id) + { + try + { + return _context.Exercises.Find(id); + } + catch (Exception ex) + { + throw; + } + } + + void IRepository.Update(Exercise exercise) + { + try + { + _context.Exercises.Update(exercise); + _context.SaveChanges(); + } + catch (Exception ex) + { + throw; + } + } +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Repositories/IRepository.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Repositories/IRepository.cs new file mode 100644 index 00000000..fa81a51c --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Repositories/IRepository.cs @@ -0,0 +1,12 @@ +using ExerciseTracker.Models; + +namespace ExerciseTracker.Repositories; + +public interface IRepository +{ + Exercise GetById(int id); + IEnumerable GetAll(); + void Add(Exercise exercise); + void Update(Exercise exercise); + void Delete(Exercise exercise); +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Services/ExerciseService.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Services/ExerciseService.cs new file mode 100644 index 00000000..187bf3bf --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Services/ExerciseService.cs @@ -0,0 +1,47 @@ +using ExerciseTracker.Models; +using ExerciseTracker.Repositories; + +namespace ExerciseTracker.Services; + +public class ExerciseService : IService +{ + public IRepository _exerciseRepository; + public ExerciseService(IRepository exerciseRepository) + { + _exerciseRepository = exerciseRepository; + } + + public void Add(Exercise exercise) + { + _exerciseRepository.Add(exercise); + } + + public void Update(Exercise exercise) + { + _exerciseRepository.Update(exercise); + } + + public void Delete(Exercise exercise) + { + _exerciseRepository.Delete(exercise); + } + + public Exercise GetById(int id) + { + return _exerciseRepository.GetById(id); + } + + public IEnumerable GetAll() + { + + return _exerciseRepository.GetAll(); + } + + public IEnumerable GetLast10() + { + return GetAll() + .OrderByDescending(x => x.Id) + .Take(10) + .ToList(); + } +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Services/IService.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Services/IService.cs new file mode 100644 index 00000000..8fd56ac3 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Services/IService.cs @@ -0,0 +1,15 @@ +using ExerciseTracker.Models; + +namespace ExerciseTracker.Services +{ + public interface IService + { + void Add(Exercise exercise); + void Delete(Exercise exercise); + void Update(Exercise exercise); + Exercise GetById(int id); + IEnumerable GetAll(); + IEnumerable GetLast10(); + + } +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/UI/UserInput.cs b/ExerciseTracker.AnaClos/ExerciseTracker/UI/UserInput.cs new file mode 100644 index 00000000..a159dd90 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/UI/UserInput.cs @@ -0,0 +1,71 @@ +using Spectre.Console; +using ExerciseTracker.DTO; + +namespace ExerciseTracker.UI; + +public class UserInput +{ + public string Menu(string title, string color, List mainOptions) + { + Console.Clear(); + + var selection = AnsiConsole.Prompt( + new SelectionPrompt() + .Title($"[{color}]{title}[/]") + .PageSize(10) + .AddChoices(mainOptions)); + + return selection; + } + + public string GetString(string message) + { + return AnsiConsole.Prompt(new TextPrompt($@"[bold blue]{message} [/]")); + } + + public void ShowMessage(string message, string color) + { + AnsiConsole.MarkupLine($"[{color}]{message}[/]\n"); + } + + public void PressKey(string message) + { + ShowMessage(message, "blue"); + Console.ReadKey(); + Console.Clear(); + } + + public void MessageAndPressKey(string message, string color) + { + ShowMessage(message, color); + PressKey("Press any key to continue"); + } + + public void ShowTable(string title, string[] columns, List records) + { + var table = new Table(); + table.Title(title); + foreach (var column in columns) + { + table.AddColumn(column); + } + + foreach (var record in records) + { + table.AddRow(record.Column1, record.Column2); + } + + AnsiConsole.Write(table); + } + + public bool Choice(string prompt) + { + var confirmation = AnsiConsole.Prompt( + new TextPrompt(prompt) + .AddChoice(true) + .AddChoice(false) + .DefaultValue(true) + .WithConverter(choice => choice ? "y" : "n")); + return confirmation; + } +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/Validators/ExerciseValidator.cs b/ExerciseTracker.AnaClos/ExerciseTracker/Validators/ExerciseValidator.cs new file mode 100644 index 00000000..5b126ec2 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/Validators/ExerciseValidator.cs @@ -0,0 +1,26 @@ +using ExerciseTracker.Models; +using System.Globalization; + +namespace ExerciseTracker.Validators; + +public class ExerciseValidator +{ + public static bool IntervalValidator(DateTime start, DateTime end) + { + TimeSpan timeSpan = end - start; + double eightHours = 3600 * 8; + return timeSpan.TotalSeconds > 0 && timeSpan.TotalSeconds <= eightHours ? true : false; + } + + public static DateTime DateTimeValidator(string date) + { + DateTime dateTime = DateTime.MinValue; + DateTime.TryParseExact(date, "yy/MM/dd HH:mm:ss", new CultureInfo("en-US"), DateTimeStyles.None, out dateTime); + return dateTime; + } + + public static bool OrderValidator(Exercise lastShift, DateTime newStartTime) + { + return newStartTime - lastShift.DateEnd >= TimeSpan.Zero ? true : false; + } +} \ No newline at end of file diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/appsettings.Development.json b/ExerciseTracker.AnaClos/ExerciseTracker/appsettings.Development.json new file mode 100644 index 00000000..120e5a62 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Microsoft.EntityFrameworkCore.Database.Command": "None" + } + } +} diff --git a/ExerciseTracker.AnaClos/ExerciseTracker/appsettings.json b/ExerciseTracker.AnaClos/ExerciseTracker/appsettings.json new file mode 100644 index 00000000..b9838bf6 --- /dev/null +++ b/ExerciseTracker.AnaClos/ExerciseTracker/appsettings.json @@ -0,0 +1,13 @@ +{ + "ConnectionStrings": { + "ExerciseTrackerConnection": "Server=DESKTOP-H645C4H\\SQLEXPRESS;Database=ExerciseTracker;Trusted_Connection=True;TrustServerCertificate=True;" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Microsoft.EntityFrameworkCore.Database.Command": "None" + } + }, + "AllowedHosts": "*" +} diff --git a/ExerciseTracker.AnaClos/Readme.txt b/ExerciseTracker.AnaClos/Readme.txt new file mode 100644 index 00000000..d7d24b5c --- /dev/null +++ b/ExerciseTracker.AnaClos/Readme.txt @@ -0,0 +1,14 @@ +# Console Exercise Tracker +## Description +This program allows you to store exercises in a database. +## Database +For the program to work, a database must be created in SQL Server. In this case, Windows credentials were used. +## Configuration +The person who wants to test or use this program must modify the ConnectionString in appsettings.json and adapt it to their SQLServer configuration. +## Limitations +Only the last 10 exercises are displayed. +There is no daily hour limit. +Only the last record can be deleted or edited. +## Improvements +Select a month and year to display a summary of Exercises. +Improve the way it is displayed.