diff --git a/Drinks-App.csproj b/Drinks-App.csproj new file mode 100644 index 00000000..8483b8a2 --- /dev/null +++ b/Drinks-App.csproj @@ -0,0 +1,17 @@ + + + + Exe + net9.0 + Drinks_App + enable + enable + + + + + + + + + diff --git a/Drinks-App.sln b/Drinks-App.sln new file mode 100644 index 00000000..6559ccd5 --- /dev/null +++ b/Drinks-App.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Drinks-App", "Drinks-App.csproj", "{B047A06B-5EBC-A5CD-3168-16CC1D06A23F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B047A06B-5EBC-A5CD-3168-16CC1D06A23F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B047A06B-5EBC-A5CD-3168-16CC1D06A23F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B047A06B-5EBC-A5CD-3168-16CC1D06A23F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B047A06B-5EBC-A5CD-3168-16CC1D06A23F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0CC91901-3627-45F7-B887-53A9EFCADBE9} + EndGlobalSection +EndGlobal diff --git a/DrinksService.cs b/DrinksService.cs new file mode 100644 index 00000000..100e4fe8 --- /dev/null +++ b/DrinksService.cs @@ -0,0 +1,101 @@ +using Drinks_App.Models; +using Newtonsoft.Json; +using RestSharp; +using System.Reflection; +using System.Web; +using static Drinks_App.Models.Drink; +using static Drinks_App.Models.DrinkDetails; + +namespace Drinks_App +{ + internal class DrinksService + { + internal List GetCategories() + { + var client = new RestClient("http://www.thecocktaildb.com/api/json/v1/1/"); + var request = new RestRequest("list.php?c=list"); + var response = client.ExecuteAsync(request); + + List categories = new(); + + if (response.Result.StatusCode == System.Net.HttpStatusCode.OK) + { + string rawResponse = response.Result.Content; + var serialise = JsonConvert.DeserializeObject(rawResponse); + + categories = serialise.CategoriesList; + + TableVisualizationEngine.ShowTable(categories, "Categories Menu"); + + return categories; + } + return categories; + } + internal List GetDrinks(string? category) + { + var client = new RestClient("http://www.thecocktaildb.com/api/json/v1/1/"); + var request = new RestRequest($"filter.php?c={ HttpUtility.UrlEncode(category)}"); + var response = client.ExecuteAsync(request); + + List drinks = new(); + + if (response.Result.StatusCode == System.Net.HttpStatusCode.OK) + { + string rawResponse = response.Result.Content; + var serialise = JsonConvert.DeserializeObject(rawResponse); + + drinks = serialise.DrinksList; + + TableVisualizationEngine.ShowTable(drinks, "Drinks Menu"); + + return drinks; + } + + return drinks; + } + + internal void GetDrink(string? drinkId) + { + var client = new RestClient("http://www.thecocktaildb.com/api/json/v1/1/"); + var request = new RestRequest($"lookup.php?i={HttpUtility.UrlEncode(drinkId)}"); + var response = client.ExecuteAsync(request); + + if (response.Result.StatusCode == System.Net.HttpStatusCode.OK) + { + string rawResponse = response.Result.Content; + var serialise = JsonConvert.DeserializeObject(rawResponse); + + List returnedList = serialise.DrinkDetailList; + + DrinkDetail drinkDetail = returnedList[0]; + + List prepList = new(); + + + string formattedName = ""; + + foreach (PropertyInfo prop in drinkDetail.GetType().GetProperties()) + { + + if (prop.Name.Contains("str")) + { + formattedName = prop.Name.Substring(3); + } + + if (!string.IsNullOrEmpty(prop.GetValue(drinkDetail)?.ToString())) + { + prepList.Add(new + { + Key = formattedName, + Value = prop.GetValue(drinkDetail) + }); + } + } + + TableVisualizationEngine.ShowTable(prepList, drinkDetail.strDrink); + + } + } + + } +} diff --git a/Models/Category.cs b/Models/Category.cs new file mode 100644 index 00000000..97d37b68 --- /dev/null +++ b/Models/Category.cs @@ -0,0 +1,16 @@ + +using Newtonsoft.Json; + +namespace Drinks_App.Models +{ + public class Category + { + public string strCategory { get; set; } + } + + public class Categories + { + [JsonProperty("drinks")] + public List CategoriesList { get; set; } + } +} diff --git a/Models/Drink.cs b/Models/Drink.cs new file mode 100644 index 00000000..28c02942 --- /dev/null +++ b/Models/Drink.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Drinks_App.Models +{ + public class Drinks + { + [JsonProperty("drinks")] + public List DrinksList { get; set; } + } + + public class Drink + { + public string idDrink { get; set; } + public string strDrink { get; set; } + } +} diff --git a/Models/DrinkDetails.cs b/Models/DrinkDetails.cs new file mode 100644 index 00000000..7f1a2a16 --- /dev/null +++ b/Models/DrinkDetails.cs @@ -0,0 +1,66 @@ +using Newtonsoft.Json; + +namespace Drinks_App.Models +{ + internal class DrinkDetails + { + internal class DrinkDetailObject + { + [JsonProperty("drinks")] + public List DrinkDetailList { get; set; } + } + internal class DrinkDetail + { + public string strDrink { get; set; } + public object strDrinkAlternate { get; set; } + public object strTags { get; set; } + public object strVideo { get; set; } + public string strCategory { get; set; } + public object strIBA { get; set; } + public string strAlcoholic { get; set; } + public string strGlass { get; set; } + public string strInstructions { get; set; } + public object strInstructionsES { get; set; } + public string strInstructionsDE { get; set; } + public object strInstructionsFR { get; set; } + public string strInstructionsIT { get; set; } + public object strInstructionsZHHANS { get; set; } + public object strInstructionsZHHANT { get; set; } + public string strDrinkThumb { get; set; } + public string strIngredient1 { get; set; } + public string strIngredient2 { get; set; } + public string strIngredient3 { get; set; } + public string strIngredient4 { get; set; } + public object strIngredient5 { get; set; } + public object strIngredient6 { get; set; } + public object strIngredient7 { get; set; } + public object strIngredient8 { get; set; } + public object strIngredient9 { get; set; } + public object strIngredient10 { get; set; } + public object strIngredient11 { get; set; } + public object strIngredient12 { get; set; } + public object strIngredient13 { get; set; } + public object strIngredient14 { get; set; } + public object strIngredient15 { get; set; } + public string strMeasure1 { get; set; } + public string strMeasure2 { get; set; } + public string strMeasure3 { get; set; } + public string strMeasure4 { get; set; } + public object strMeasure5 { get; set; } + public object strMeasure6 { get; set; } + public object strMeasure7 { get; set; } + public object strMeasure8 { get; set; } + public object strMeasure9 { get; set; } + public object strMeasure10 { get; set; } + public object strMeasure11 { get; set; } + public object strMeasure12 { get; set; } + public object strMeasure13 { get; set; } + public object strMeasure14 { get; set; } + public object strMeasure15 { get; set; } + public object strImageSource { get; set; } + public object strImageAttribution { get; set; } + public string strCreativeCommonsConfirmed { get; set; } + public string dateModified { get; set; } + } + } +} diff --git a/Program.cs b/Program.cs new file mode 100644 index 00000000..7ea29783 --- /dev/null +++ b/Program.cs @@ -0,0 +1,5 @@ +using Drinks_App; + +UserInput userInput = new(); + +userInput.GetCategoriesInput(); \ No newline at end of file diff --git a/TableVisualizationEngine.cs b/TableVisualizationEngine.cs new file mode 100644 index 00000000..6cbafa75 --- /dev/null +++ b/TableVisualizationEngine.cs @@ -0,0 +1,36 @@ +using System.Diagnostics.CodeAnalysis; +using ConsoleTableExt; + +namespace Drinks_App +{ + class TableVisualizationEngine + { + /* + * Displays any list of objects as a console table. + * + * is a generic type parameter: + * - When you call this method, T becomes the actual model type + * (e.g., User, Product, Order, etc.). + * - This allows a single method to handle tables for any model, + * instead of writing one method per model type. + * + * tableData : List → the list of objects to print + * tableName : string? → optional header name (can be null) + */ + public static void ShowTable (List TableData, [AllowNull] string TableName) where T : class + { + Console.Clear(); + + if (TableName == null) TableName = ""; + + Console.WriteLine("\n\n"); + + ConsoleTableBuilder + .From(TableData).WithColumn(TableName).WithFormat(ConsoleTableBuilderFormat.Alternative) + .ExportAndWriteLine(TableAligntment.Center); + + Console.WriteLine("\n\n"); + + } + } +} diff --git a/UserInput.cs b/UserInput.cs new file mode 100644 index 00000000..f20c8456 --- /dev/null +++ b/UserInput.cs @@ -0,0 +1,59 @@ + +using Drinks_App.Models; + +namespace Drinks_App +{ + internal class UserInput + { + DrinksService drinksService = new(); + + internal void GetCategoriesInput () + { + var categories = drinksService.GetCategories(); + + Console.WriteLine("Select a Category"); + string category = Console.ReadLine(); + + while(!Validator.ValidCategory(category)) + { + Console.WriteLine("Invalid Category"); + category = Console.ReadLine(); + } + + if (!categories.Any(x => x.strCategory == category)) + { + Console.WriteLine("Category doesn't exist."); + GetCategoriesInput(); + } + + GetDrinksByCategory(category); + } + + public void GetDrinksByCategory(string? category) + { + var drinks = drinksService.GetDrinks(category); + + Console.WriteLine("Choose a Drink Id or Enter 0 to return to Categories Menue"); + + string drinkId = Console.ReadLine(); + + if(drinkId == "0") + { + GetCategoriesInput(); + } + while(!Validator.ValidateDrinkId(drinkId)) + { + Console.WriteLine("Invalid Drink"); + drinkId = Console.ReadLine(); + } + if (!drinks.Any(x => x.idDrink == drinkId)) + { + Console.WriteLine("Drink doesn't exist."); + GetDrinksByCategory(category); + } + + + drinksService.GetDrink(drinkId); + } + } +} diff --git a/Validator.cs b/Validator.cs new file mode 100644 index 00000000..71998d08 --- /dev/null +++ b/Validator.cs @@ -0,0 +1,49 @@ +using Drinks_App.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Drinks_App +{ + class Validator + { + + + internal static bool ValidCategory(string? category) + { + if(string.IsNullOrEmpty(category)) + { + return false; + } + + foreach (char c in category) + { + if (!Char.IsLetter(c) && c != '/' && c != ' ') + { + return false; + } + } + + return true; + } + internal static bool ValidateDrinkId(string? drinkId) + { + if (string.IsNullOrEmpty(drinkId)) + { + return false; + } + + foreach (char c in drinkId) + { + if (!Char.IsDigit(c)) + { + return false; + } + } + + return true; + } + } +}