diff --git a/DrinkInfoPractice/DrinkInfoPractice.sln b/DrinkInfoPractice/DrinkInfoPractice.sln
new file mode 100644
index 00000000..2b262649
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.12.35707.178 d17.12
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DrinkInfoPractice", "DrinkInfoPractice\DrinkInfoPractice.csproj", "{8FF8B80C-BF62-4C83-9773-1C8728D60E19}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8FF8B80C-BF62-4C83-9773-1C8728D60E19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8FF8B80C-BF62-4C83-9773-1C8728D60E19}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8FF8B80C-BF62-4C83-9773-1C8728D60E19}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8FF8B80C-BF62-4C83-9773-1C8728D60E19}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/DrinkInfoPractice/DrinkInfoPractice/DrinkInfoPractice.csproj b/DrinkInfoPractice/DrinkInfoPractice/DrinkInfoPractice.csproj
new file mode 100644
index 00000000..e2f26fa9
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/DrinkInfoPractice.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
diff --git a/DrinkInfoPractice/DrinkInfoPractice/Interfaces/ICocktailService.cs b/DrinkInfoPractice/DrinkInfoPractice/Interfaces/ICocktailService.cs
new file mode 100644
index 00000000..2ce72f79
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/Interfaces/ICocktailService.cs
@@ -0,0 +1,10 @@
+using DrinkInfoPractice.Models;
+
+namespace DrinkInfoPractice.Interfaces;
+
+internal interface ICocktailService
+{
+ Task> GetCategoriesAsync();
+ Task> GetDrinksByCategoryAsync(string category);
+ Task GetDrinkByIdAsync(string id);
+}
diff --git a/DrinkInfoPractice/DrinkInfoPractice/Models/ApiResponse.cs b/DrinkInfoPractice/DrinkInfoPractice/Models/ApiResponse.cs
new file mode 100644
index 00000000..45af2c39
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/Models/ApiResponse.cs
@@ -0,0 +1,9 @@
+using System.Text.Json.Serialization;
+
+namespace DrinkInfoPractice.Models;
+
+internal class ApiResponse
+{
+ [JsonPropertyName("drinks")]
+ public List Drinks { get; set; }
+}
diff --git a/DrinkInfoPractice/DrinkInfoPractice/Models/DrinkCategory.cs b/DrinkInfoPractice/DrinkInfoPractice/Models/DrinkCategory.cs
new file mode 100644
index 00000000..56549875
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/Models/DrinkCategory.cs
@@ -0,0 +1,9 @@
+using System.Text.Json.Serialization;
+
+namespace DrinkInfoPractice.Models;
+
+internal class DrinkCategory
+{
+ [JsonPropertyName("strCategory")]
+ public string StrCategory { get; set; }
+}
diff --git a/DrinkInfoPractice/DrinkInfoPractice/Models/DrinkDetail.cs b/DrinkInfoPractice/DrinkInfoPractice/Models/DrinkDetail.cs
new file mode 100644
index 00000000..c7226f10
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/Models/DrinkDetail.cs
@@ -0,0 +1,34 @@
+using System.Text.Json.Serialization;
+
+namespace DrinkInfoPractice.Models;
+
+internal class DrinkDetail
+{
+ [JsonPropertyName("idDrink")]
+ public string IdDrink { get; set; }
+
+ [JsonPropertyName("strDrink")]
+ public string StrDrink { get; set; }
+
+ [JsonPropertyName("strCategory")]
+ public string StrCategory { get; set; }
+
+ [JsonPropertyName("strGlass")]
+ public string StrGlass { get; set; }
+
+ [JsonPropertyName("strInstructions")]
+ public string StrInstructions { get; set; }
+
+ private Dictionary _ingredients = new();
+
+ public IReadOnlyDictionary Ingredients => _ingredients;
+
+ public void AddIngredient(int index, string ingredient, string measure)
+ {
+ if (!string.IsNullOrWhiteSpace(ingredient))
+ {
+ _ingredients[index] = (ingredient, measure);
+ }
+ }
+
+}
diff --git a/DrinkInfoPractice/DrinkInfoPractice/Models/DrinkSummary.cs b/DrinkInfoPractice/DrinkInfoPractice/Models/DrinkSummary.cs
new file mode 100644
index 00000000..11c7504a
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/Models/DrinkSummary.cs
@@ -0,0 +1,15 @@
+using System.Text.Json.Serialization;
+
+namespace DrinkInfoPractice.Models;
+
+internal class DrinkSummary
+{
+ [JsonPropertyName("idDrink")]
+ public string IdDrink { get; set; }
+
+ [JsonPropertyName("strDrink")]
+ public string StrDrink { get; set; }
+
+ [JsonPropertyName("strDrinkThumb")]
+ public string StrDrinkThumb { get; set; }
+}
diff --git a/DrinkInfoPractice/DrinkInfoPractice/Program.cs b/DrinkInfoPractice/DrinkInfoPractice/Program.cs
new file mode 100644
index 00000000..79f9f570
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/Program.cs
@@ -0,0 +1,3 @@
+using DrinkInfoPractice.Services;
+UserInput userInput = new UserInput();
+await userInput.Start();
\ No newline at end of file
diff --git a/DrinkInfoPractice/DrinkInfoPractice/Services/CocktailService.cs b/DrinkInfoPractice/DrinkInfoPractice/Services/CocktailService.cs
new file mode 100644
index 00000000..340e6329
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/Services/CocktailService.cs
@@ -0,0 +1,128 @@
+using DrinkInfoPractice.Interfaces;
+using DrinkInfoPractice.Models;
+using System.Text.Json;
+
+
+namespace DrinkInfoPractice.Services;
+
+internal class CocktailService : ICocktailService
+{
+ // filed for stroing HttpClient
+ private readonly HttpClient _httpClient;
+
+ // API's base url
+ private const string BaseUrl = "http://www.thecocktaildb.com/api/json/v1/1/";
+
+ public CocktailService()
+ {
+ _httpClient = new HttpClient();
+
+ // setting the base address
+ _httpClient.BaseAddress = new Uri(BaseUrl);
+ }
+
+ public async Task> GetCategoriesAsync()
+ {
+ try
+ {
+ // making the API call
+ var response = await _httpClient.GetAsync("list.php?c=list");
+
+
+ // check to see if call was successful
+ response.EnsureSuccessStatusCode();
+
+ // read the response content
+ var content = await response.Content.ReadAsStringAsync();
+
+
+ // convert the JSON to our C# objects
+ // takes the json and creates DrinkCategory object
+ var result = JsonSerializer.Deserialize>(content);
+
+
+ //return list of categories
+ // if result or Drinks is null, return empty list
+ return result?.Drinks ?? new List();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error getting categories: {ex.Message}");
+ throw;
+ }
+ }
+
+ public async Task> GetDrinksByCategoryAsync(string category)
+ {
+ try
+ {
+ // API call
+ var response = await _httpClient.GetAsync($"filter.php?c={category}");
+
+ response.EnsureSuccessStatusCode();
+
+ var content = await response.Content.ReadAsStringAsync();
+
+ var result = JsonSerializer.Deserialize>(content);
+
+ return result?.Drinks ?? new List();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error getting drink summary: {ex.Message}");
+ throw;
+ }
+ }
+
+ public async Task GetDrinkByIdAsync(string id)
+ {
+ try
+ {
+ // API call
+ var response = await _httpClient.GetAsync($"lookup.php?i={id}");
+
+ response.EnsureSuccessStatusCode();
+
+ var content = await response.Content.ReadAsStringAsync();
+
+ var result = JsonSerializer.Deserialize>(content);
+
+ var drink = result?.Drinks?.FirstOrDefault();
+
+ if (drink != null)
+ {
+ // Then process ingredients from the JSON directly
+ using (JsonDocument document = JsonDocument.Parse(content))
+ {
+ var drinkElement = document.RootElement.GetProperty("drinks")[0];
+
+ // Process ingredients
+ for (int i = 1; i <= 15; i++)
+ {
+ if (drinkElement.TryGetProperty($"strIngredient{i}", out JsonElement ingredientElement) &&
+ ingredientElement.ValueKind != JsonValueKind.Null)
+ {
+ var ingredient = ingredientElement.GetString();
+ var measure = "As needed";
+
+ if (drinkElement.TryGetProperty($"strMeasure{i}", out JsonElement measureElement) &&
+ measureElement.ValueKind != JsonValueKind.Null)
+ {
+ measure = measureElement.GetString();
+ }
+
+ drink.AddIngredient(i, ingredient, measure);
+ }
+ }
+ }
+ }
+
+ return drink ?? new DrinkDetail();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error getting drink details: {ex.Message}");
+ throw;
+ }
+ }
+}
diff --git a/DrinkInfoPractice/DrinkInfoPractice/Services/TableVisualization.cs b/DrinkInfoPractice/DrinkInfoPractice/Services/TableVisualization.cs
new file mode 100644
index 00000000..c2adb00c
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/Services/TableVisualization.cs
@@ -0,0 +1,47 @@
+using DrinkInfoPractice.Models;
+using Spectre.Console;
+
+namespace DrinkInfoPractice.Services;
+
+internal class TableVisualization
+{
+ internal static void ShowTable(DrinkDetail drinkDetail)
+ {
+ List ingredientList = new List();
+ foreach (var ingredient in drinkDetail.Ingredients)
+ {
+ ingredientList.Add($"- {ingredient.Value.Ingredients}: {ingredient.Value.Measure}");
+ }
+
+ string? ingredients = string.Join("\n", ingredientList);
+
+ Console.WriteLine("\n");
+
+ Table table = new Table();
+
+ table.AddColumn("Drink ID");
+ table.AddColumn("Drink");
+ table.AddColumn("Category");
+ table.AddColumn("Glass");
+ table.AddColumn("Instructions");
+ table.AddColumn("Ingredients");
+
+ table.AddRow(
+ drinkDetail.IdDrink,
+ drinkDetail.StrDrink,
+ drinkDetail.StrCategory,
+ drinkDetail.StrGlass,
+ drinkDetail.StrInstructions,
+ ingredients
+ );
+
+ table.Border(TableBorder.Square);
+ table.BorderColor(Color.Blue);
+
+ AnsiConsole.Write(table);
+
+ Console.WriteLine("Press Enter");
+ Console.ReadLine();
+
+ }
+}
diff --git a/DrinkInfoPractice/DrinkInfoPractice/Services/UserInput.cs b/DrinkInfoPractice/DrinkInfoPractice/Services/UserInput.cs
new file mode 100644
index 00000000..dec34b3c
--- /dev/null
+++ b/DrinkInfoPractice/DrinkInfoPractice/Services/UserInput.cs
@@ -0,0 +1,72 @@
+using Spectre.Console;
+
+namespace DrinkInfoPractice.Services;
+
+internal class UserInput
+{
+ CocktailService cocktailService = new CocktailService();
+
+ internal async Task Start()
+ {
+ bool continueRun = true;
+ while (continueRun)
+ {
+ Console.Clear();
+
+ string category = await CategoryMenu();
+
+ string id = await DrinksMenu(category);
+
+ TableVisualization.ShowTable(await cocktailService.GetDrinkByIdAsync(id));
+
+ continueRun = ContinueRun();
+ }
+ }
+
+ internal bool ContinueRun()
+ {
+ var choice = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("Would you like to find another drink?")
+ .AddChoices(new[]
+ {
+ "Yes",
+ "No"
+ }));
+ return choice == "Yes";
+ }
+
+ private async Task DrinksMenu(string category)
+ {
+ var drinks = await cocktailService.GetDrinksByCategoryAsync(category);
+
+ Dictionary drinkMapping = drinks.ToDictionary(d => d.StrDrink, d => d.IdDrink);
+
+ var drinkNames = drinkMapping.Keys.ToList();
+
+ var choice = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("Select a drink")
+ .AddChoices(drinkNames));
+
+ string id = drinkMapping[choice].ToString();
+ return id;
+ }
+
+ internal async Task CategoryMenu()
+ {
+ var categories = await cocktailService.GetCategoriesAsync();
+
+ var categoryNames = categories.Select(c => c.StrCategory).ToList();
+ categoryNames.Add("Exit");
+
+ var category = AnsiConsole.Prompt(
+ new SelectionPrompt()
+ .Title("Selection the category of drink.")
+ .AddChoices(categoryNames));
+
+ if (category == "Exit") Environment.Exit(0);
+
+ return category;
+ }
+}