diff --git a/src/EasyList/DataModels/Todo.cs b/src/EasyList/DataModels/Todo.cs index 8855bfc..7e9b0b9 100644 --- a/src/EasyList/DataModels/Todo.cs +++ b/src/EasyList/DataModels/Todo.cs @@ -18,10 +18,8 @@ public class Todo public string Label { get; set; } public string? Description { get; set; } public TodoPriority Priority { get; set; } = TodoPriority.Low; - private DateTimeOffset _createdDate = DateTimeOffset.UtcNow; public DateTimeOffset CreatedDate => _createdDate.ToLocalTime(); - private DateTimeOffset? _dueDate; public DateTimeOffset? DueDate { diff --git a/src/EasyList/Enums/TodoMenuOptions.cs b/src/EasyList/Enums/TodoMenuOptions.cs index b2c5826..bcb58aa 100644 --- a/src/EasyList/Enums/TodoMenuOptions.cs +++ b/src/EasyList/Enums/TodoMenuOptions.cs @@ -7,6 +7,7 @@ public enum TODOMENU View, MarkAsDone, ListAll, + Update, Quit } } \ No newline at end of file diff --git a/src/EasyList/Enums/TodoUpdate.cs b/src/EasyList/Enums/TodoUpdate.cs new file mode 100644 index 0000000..401b523 --- /dev/null +++ b/src/EasyList/Enums/TodoUpdate.cs @@ -0,0 +1,10 @@ +namespace EasyList +{ + public enum TodoUpdate + { + Label, + Description, + Priority, + DueDate + } +} \ No newline at end of file diff --git a/src/EasyList/Interfaces/ITodoService.cs b/src/EasyList/Interfaces/ITodoService.cs index d657901..c630c38 100644 --- a/src/EasyList/Interfaces/ITodoService.cs +++ b/src/EasyList/Interfaces/ITodoService.cs @@ -11,5 +11,6 @@ internal interface ITodoService void DisplayAllTodo(TodoOrder todoOrder); Todo? GetTodoByID(int id); void MarkTodoAsDone(Todo todo); + void UpdateTodo(Todo todo, TodoUpdate command); } } \ No newline at end of file diff --git a/src/EasyList/ParseAdd.cs b/src/EasyList/ParseAdd.cs index 3aec697..8f36748 100644 --- a/src/EasyList/ParseAdd.cs +++ b/src/EasyList/ParseAdd.cs @@ -52,10 +52,9 @@ public static Dictionary Parse(string[] args) } string label = GetData("add", args, positions) ?? string.Empty; - string description = GetData("-d", args, positions) ?? string.Empty; string dueDate = GetData("-t", args, positions) ?? string.Empty; - string priority = GetData("-p", args, positions) ?? "${TodoPriority.Low}"; + string priority = GetData("-p", args, positions) ?? $"{TodoPriority.Low}"; return new Dictionary { {"label" ,label }, diff --git a/src/EasyList/Program.cs b/src/EasyList/Program.cs index 7e06e05..6e9ecc7 100644 --- a/src/EasyList/Program.cs +++ b/src/EasyList/Program.cs @@ -1,7 +1,12 @@ -namespace EasyList +using EasyList.Factories; +using EasyList.Interfaces; + +namespace EasyList { class Program { + public static ITodoService TodoService => Factory.CreateTodoServiceDB(); + public static void Main(string[] args) { if(args.Length > 1) diff --git a/src/EasyList/TodoMenu.cs b/src/EasyList/TodoMenu.cs index 599487d..8b82bcc 100644 --- a/src/EasyList/TodoMenu.cs +++ b/src/EasyList/TodoMenu.cs @@ -1,138 +1,100 @@ using EasyList.DataModels; using EasyList.Enums; -using EasyList.Factories; -using EasyList.Interfaces; using Sharprompt; using System; using System.Collections.Generic; -using System.Linq; namespace EasyList { public class TodoMenu { - private static IEnumerable ValidateAdd(Dictionary input) - { - if (string.IsNullOrWhiteSpace(input["label"])) - { - yield return "Label cannot be empty"; - } - if (DateTimeOffset.TryParse(input["duedate"], out DateTimeOffset tempDate)) - { - if (tempDate < DateTime.UtcNow) - { - yield return "Due date cannot be in the past"; - } - } - } - - private static bool Validate(TODOMENU command, Dictionary input) - { - var errors = command switch { - TODOMENU.Add => ValidateAdd(input), - // register the rest of the options that need to be validated here - _ => throw new InvalidOperationException($"No validator exists for {command}"), - }; - - if (errors.Any()) - { - Console.WriteLine("The input has the following errors:"); - foreach (var error in errors) - { - Console.WriteLine("\t"+error); - } - - return false; - } - - return true; - } public static void Run() { - ITodoService _todoService = Factory.CreateTodoServiceDB(); - while(true) + var _todoValidate = new Validate(); + while (true) { var action = Prompt.Select("Welcome to EasyList!"); //Refactor this such that adding new should not modify this input layer switch (action) { + case TODOMENU.Add: - var inputAdd = Prompt.Input("Enter TODO "); - var parsedAdd = ParseAdd.Parse(inputAdd?.Split() ?? Array.Empty()); - - if (Validate(action, parsedAdd)) { - var newTodo = new Todo() + var inputAdd = Prompt.Input("Enter TODO "); + var parsedAdd = ParseAdd.Parse(inputAdd?.Split() ?? Array.Empty()); + + if (_todoValidate.IsAddValid(parsedAdd)) { - Label = parsedAdd["label"], - Description = parsedAdd["description"], - DueDate = DateTimeOffset.TryParse(parsedAdd["duedate"], out DateTimeOffset tempDate) ? tempDate : null, - Priority = Enum.Parse(parsedAdd["priority"]) - }; - _todoService.AddTodo(newTodo); + var newTodo = new Todo() + { + Label = parsedAdd["label"], + Description = parsedAdd["description"], + DueDate = DateTimeOffset.TryParse(parsedAdd["duedate"], out DateTimeOffset tempDate) ? tempDate : null, + Priority = Enum.Parse(parsedAdd["priority"]) + }; + Program.TodoService.AddTodo(newTodo); + } + break; } - - break; - case TODOMENU.Delete: - var inputDelete = Prompt.Input("Enter TODO ID(s) "); - foreach (var item in inputDelete.Split()) + var inputDelete = Prompt.Input("Enter TODO ID(s) ").Split(); + + if (_todoValidate.IsDeleteValid(inputDelete,out List todoDeleteList)) { - var todoItem = _todoService.GetTodoByID(int.Parse(item)); - if(todoItem != null) + foreach (var todoDelete in todoDeleteList) { - Console.WriteLine($"Deleted: {todoItem.Label}"); - _todoService.DeleteTodo(todoItem); - } - else - { - Console.WriteLine($"Todo Id: {item} Not Found."); - Console.WriteLine("Try Again."); - } - + Program.TodoService.DeleteTodo(todoDelete); + } } break; case TODOMENU.View: - var inputView = Prompt.Input("Enter TODO ID "); - var todo = _todoService.GetTodoByID(inputView); - if(todo != null) { - _todoService.DisplayTodo(todo); - } - else - { - Console.WriteLine($"Todo Id: {inputView} Not Found."); + var inputView = Prompt.Input("Enter TODO ID "); + + if (_todoValidate.IsReadValid(inputView, out Todo validTodo)) + { + Program.TodoService.DisplayTodo(validTodo); + } + break; } - break; - case TODOMENU.MarkAsDone: - var inputDone = Prompt.Input("Enter TODO ID(s) "); - foreach (var item in inputDone.Split()) { - var todoItem = _todoService.GetTodoByID(int.Parse(item)); - if(todoItem != null) + var inputDone = Prompt.Input("Enter TODO ID(s) ").Split(); + + if (_todoValidate.CanMarkAsDone(inputDone, out List doneTodoList)) { - Console.WriteLine($"Completed:{todoItem.Label}."); - _todoService.MarkTodoAsDone(todoItem); + foreach (var doneTodo in doneTodoList) + { + Program.TodoService.MarkTodoAsDone(doneTodo); + } } - else + break; + } + case TODOMENU.Update: + { + var inputUpdateAction = Prompt.Select("Select Update Action"); + var inputUpdate = Prompt.Input("Enter the ID to Update"); + + if (_todoValidate.IsReadValid(inputUpdate, out Todo validTodo)) { - Console.WriteLine($"Todo Id: {item} Not Found."); - Console.WriteLine("Try Again."); + Program.TodoService.UpdateTodo(validTodo, inputUpdateAction); } + break; } - break; - case TODOMENU.ListAll: - var inputList = Prompt.Select("Select List Order: ", defaultValue: TodoOrder.CreateDate); - _todoService.DisplayAllTodo(inputList); - break; + { + var inputList = Prompt.Select("Select List Order: ", defaultValue: TodoOrder.CreateDate); + Program.TodoService.DisplayAllTodo(inputList); + break; + } case TODOMENU.Quit: - Console.WriteLine("Exiting..."); - Environment.Exit(Environment.ExitCode = 0); - break; + { + Console.WriteLine("Exiting..."); + Environment.Exit(Environment.ExitCode = 0); + break; + } } Console.ReadLine(); diff --git a/src/EasyList/TodoServiceDB.cs b/src/EasyList/TodoServiceDB.cs index 101d9e5..4d5bf87 100644 --- a/src/EasyList/TodoServiceDB.cs +++ b/src/EasyList/TodoServiceDB.cs @@ -4,6 +4,7 @@ using EasyList.Enums; using EasyList.Factories; using EasyList.Interfaces; +using Sharprompt; namespace EasyList { @@ -50,6 +51,58 @@ public void DisplayAllTodo(TodoOrder todoOrder) .Write(Format.MarkDown); } - + public void UpdateTodo(Todo todo, TodoUpdate command) + { + var _todoValidate = new Validate(); + switch (command) + { + case TodoUpdate.Label: + { + Console.WriteLine("Enter the New Label: "); + string? newLabel = Console.ReadLine(); + if (_todoValidate.IsLabelValid(newLabel)) + { + todo.Label = newLabel; + _todoRepository.UpdateTodo(todo); + Console.WriteLine("Label Updated Sucessfully."); + } + break; + } + + case TodoUpdate.Description: + { + Console.WriteLine("Enter the New Description: "); + string? newDescription = Console.ReadLine(); + if (_todoValidate.IsUpdateDescriptionValid(newDescription)) + { + todo.Description = newDescription; + _todoRepository.UpdateTodo(todo); + Console.WriteLine("Description Updated Sucessfully."); + } + break; + } + + case TodoUpdate.Priority: + { + todo.Priority = Prompt.Select("Select new Priority."); ; + _todoRepository.UpdateTodo(todo); + break; + } + + case TodoUpdate.DueDate: + { + Console.WriteLine("Enter the New Due Date: "); + string? newDueDate = Console.ReadLine(); + if(_todoValidate.IsDueDateValid(newDueDate)) + { + + todo.DueDate = DateTimeOffset.Parse(newDueDate!); + _todoRepository.UpdateTodo(todo); + Console.WriteLine("Due Date Updated Sucessfully."); + } + break; + } + } + } } } \ No newline at end of file diff --git a/src/EasyList/TodoServiceInMemory.cs b/src/EasyList/TodoServiceInMemory.cs index a74891d..d4646c1 100644 --- a/src/EasyList/TodoServiceInMemory.cs +++ b/src/EasyList/TodoServiceInMemory.cs @@ -4,6 +4,7 @@ using EasyList.Enums; using EasyList.Factories; using EasyList.Interfaces; +using Sharprompt; namespace EasyList { @@ -48,6 +49,56 @@ public void DisplayAllTodo(TodoOrder todoOrder) .Write(Format.MarkDown); } - + public void UpdateTodo(Todo todo, TodoUpdate command) + { + var _todoValidate = new Validate(); + switch (command) + { + case TodoUpdate.Label: + { + Console.WriteLine("Enter the New Label: "); + string? newLabel = Console.ReadLine(); + if (_todoValidate.IsLabelValid(newLabel)) + { + todo.Label = newLabel!; + Console.WriteLine("Label Updated Sucessfully."); + + } + break; + } + + case TodoUpdate.Description: + { + Console.WriteLine("Enter the New Description: "); + string? newDescription = Console.ReadLine(); + if (_todoValidate.IsUpdateDescriptionValid(newDescription)) + { + todo.Description = newDescription; + Console.WriteLine("Description Updated Sucessfully."); + } + break; + } + + case TodoUpdate.Priority: + { + var newPriority = Prompt.Select("Select new Priority."); + todo.Priority = newPriority; + break; + } + + case TodoUpdate.DueDate: + { + Console.WriteLine("Enter the New Due Date: "); + string? newDueDate = Console.ReadLine(); + if (_todoValidate.IsDueDateValid(newDueDate)) + { + + todo.DueDate = DateTimeOffset.Parse(newDueDate!); + Console.WriteLine("Due Date Updated Sucessfully."); + } + break; + } + } + } } } \ No newline at end of file diff --git a/src/EasyList/Utility.cs b/src/EasyList/Utility.cs new file mode 100644 index 0000000..0ee3498 --- /dev/null +++ b/src/EasyList/Utility.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; + +namespace EasyList +{ + public static class Utility + { + public static IEnumerable ToIntIds(this string[] input) + { + foreach (var item in input) + { + if (int.TryParse(item, out int num)) + { + yield return num; + } + } + } + } +} diff --git a/src/EasyList/Validate.cs b/src/EasyList/Validate.cs new file mode 100644 index 0000000..dd9faf7 --- /dev/null +++ b/src/EasyList/Validate.cs @@ -0,0 +1,135 @@ +using EasyList; +using EasyList.DataModels; +using Sharprompt; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; + +namespace EasyList +{ + public class Validate + { + private static bool IsErrorFree(IEnumerable errors) + { + if (errors.Any()) + { + Console.WriteLine("The input has the following errors:"); + foreach (var error in errors) + { + Console.WriteLine($"\t{error}"); + } + + return false; + } + return true; + } + + private void ValidateDueDate(string? input, List errors) + { + if (!string.IsNullOrEmpty(input)) + { + if (DateTimeOffset.TryParse(input, out DateTimeOffset tempDate)) + { + //do better + if (tempDate < DateTime.UtcNow) + { + errors.Add("Due date cannot be in the past"); + } + return; + } + errors.Add("Couldn't Parse Due Date."); + } + + } + + private void ValidateLabel(string? input, List errors) + { + if (string.IsNullOrWhiteSpace(input)) + { + errors.Add("Label cannot be empty"); + } + } + + public bool IsAddValid(Dictionary toAdd) + { + var errors = new List(); + ValidateLabel(toAdd["label"], errors); + ValidateDueDate(toAdd["duedate"], errors); + + return IsErrorFree(errors); + } + + public bool IsDeleteValid(IEnumerable inputDelete, out List validTodos) + { + validTodos = new List(); + return ValidateMultipleIDs(inputDelete,validTodos); + } + private bool ValidateId(string todoId, List errors,ref Todo? _todo) + { + if (!int.TryParse(todoId, out int validId)) + { + errors.Add($"Couldn't Parse {todoId}"); + return false; + } + _todo = Program.TodoService.GetTodoByID(validId); + if (_todo == null) + { + errors.Add($"Invalid Id #{validId}"); + return false; + } + return true; + } + private bool ValidateMultipleIDs(IEnumerable inputDelete, List validTodos) + { + var errors = new List(); + foreach (var todoId in inputDelete) + { + Todo? _todo = null; + if (ValidateId(todoId,errors,ref _todo)) + { + validTodos.Add(_todo!); + } + } + if (IsErrorFree(errors)) + { + return true; + } + Console.Clear(); + var choice = Prompt.Confirm("Continue with Valid Ids ? "); + Thread.Sleep(1500); + return choice; + } + + public bool CanMarkAsDone(IEnumerable inputUpdate, out List validTodos) + { + validTodos = new List(); + return ValidateMultipleIDs(inputUpdate,validTodos); + } + public bool IsReadValid(string todoID,out Todo validTodo) + { + var errors = new List(); + validTodo = null; + ValidateId(todoID, errors,ref validTodo); + return IsErrorFree(errors); + } + + public bool IsLabelValid(string label) + { + var errors = new List(); + ValidateLabel(label, errors); + return IsErrorFree(errors); + } + public bool IsDueDateValid(string dueDate) + { + var errors = new List(); + ValidateDueDate(dueDate, errors); + return IsErrorFree(errors); + } + public bool IsUpdateDescriptionValid(string description) + { + return string.IsNullOrWhiteSpace(description); + } + + } +} \ No newline at end of file