Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice.sln
Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/DrinkInfoPractice.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.49.1" />
</ItemGroup>

</Project>
10 changes: 10 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/Interfaces/ICocktailService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using DrinkInfoPractice.Models;

namespace DrinkInfoPractice.Interfaces;

internal interface ICocktailService
{
Task<List<DrinkCategory>> GetCategoriesAsync();
Task<List<DrinkSummary>> GetDrinksByCategoryAsync(string category);
Task<DrinkDetail> GetDrinkByIdAsync(string id);
}
9 changes: 9 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/Models/ApiResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Text.Json.Serialization;

namespace DrinkInfoPractice.Models;

internal class ApiResponse<T>
{
[JsonPropertyName("drinks")]
public List<T> Drinks { get; set; }
}
9 changes: 9 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/Models/DrinkCategory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Text.Json.Serialization;

namespace DrinkInfoPractice.Models;

internal class DrinkCategory
{
[JsonPropertyName("strCategory")]
public string StrCategory { get; set; }
}
34 changes: 34 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/Models/DrinkDetail.cs
Original file line number Diff line number Diff line change
@@ -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<int, (string Ingredients, string Measure)> _ingredients = new();

public IReadOnlyDictionary<int, (string Ingredients, string Measure)> Ingredients => _ingredients;

public void AddIngredient(int index, string ingredient, string measure)
{
if (!string.IsNullOrWhiteSpace(ingredient))
{
_ingredients[index] = (ingredient, measure);
}
}

}
15 changes: 15 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/Models/DrinkSummary.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
3 changes: 3 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using DrinkInfoPractice.Services;
UserInput userInput = new UserInput();
await userInput.Start();
128 changes: 128 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/Services/CocktailService.cs
Original file line number Diff line number Diff line change
@@ -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<List<DrinkCategory>> 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<ApiResponse<DrinkCategory>>(content);


//return list of categories
// if result or Drinks is null, return empty list
return result?.Drinks ?? new List<DrinkCategory>();
}
catch (Exception ex)
{
Console.WriteLine($"Error getting categories: {ex.Message}");
throw;
}
}

public async Task<List<DrinkSummary>> 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<ApiResponse<DrinkSummary>>(content);

return result?.Drinks ?? new List<DrinkSummary>();
}
catch (Exception ex)
{
Console.WriteLine($"Error getting drink summary: {ex.Message}");
throw;
}
}

public async Task<DrinkDetail> 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<ApiResponse<DrinkDetail>>(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;
}
}
}
47 changes: 47 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/Services/TableVisualization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using DrinkInfoPractice.Models;
using Spectre.Console;

namespace DrinkInfoPractice.Services;

internal class TableVisualization
{
internal static void ShowTable(DrinkDetail drinkDetail)
{
List<string> ingredientList = new List<string>();
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();

}
}
72 changes: 72 additions & 0 deletions DrinkInfoPractice/DrinkInfoPractice/Services/UserInput.cs
Original file line number Diff line number Diff line change
@@ -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<string>()
.Title("Would you like to find another drink?")
.AddChoices(new[]
{
"Yes",
"No"
}));
return choice == "Yes";
}

private async Task<string> DrinksMenu(string category)
{
var drinks = await cocktailService.GetDrinksByCategoryAsync(category);

Dictionary<string, string> drinkMapping = drinks.ToDictionary(d => d.StrDrink, d => d.IdDrink);

var drinkNames = drinkMapping.Keys.ToList();

var choice = AnsiConsole.Prompt(
new SelectionPrompt<string>()
.Title("Select a drink")
.AddChoices(drinkNames));

string id = drinkMapping[choice].ToString();
return id;
}

internal async Task<string> CategoryMenu()
{
var categories = await cocktailService.GetCategoriesAsync();

var categoryNames = categories.Select(c => c.StrCategory).ToList();
categoryNames.Add("Exit");

var category = AnsiConsole.Prompt(
new SelectionPrompt<string>()
.Title("Selection the category of drink.")
.AddChoices(categoryNames));

if (category == "Exit") Environment.Exit(0);

return category;
}
}