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
3 changes: 3 additions & 0 deletions Sangeerths.DrinkExplorer/DrinkExplorer.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Solution>
<Project Path="DrinkExplorer/DrinkExplorer.csproj" />
</Solution>
160 changes: 160 additions & 0 deletions Sangeerths.DrinkExplorer/DrinkExplorer/Controller/Menu.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
using DrinkExplorer.Services;
using DrinkExplorer.Validation;
using Spectre.Console;

namespace DrinkExplorer.Controller
{
public class Menu
{
private readonly ConsoleUI _consoleUI;
private readonly ManageDrinksService _manageDrinksService;
private readonly FavouriteDrinkService _favouriteDrinkService;
private enum CategoryOptions
{
DrinksMenu,
MyFavourites,
Exit
}

private enum DrinksOptions
{
ViewAll,
SearchDrinks,
Goback
}

private enum MyFavouritesOptions
{
ViewAll,
ViewCount,
GoBack
}

private T PromptEnum<T>(string title, params (string Label, T Value)[] options) where T : struct
{
var labels = new List<string>();
var map = new Dictionary<string, T>();
foreach (var (label, value) in options)
{
labels.Add(label);
map[label] = value;
}

string selected = AnsiConsole.Prompt(
new SelectionPrompt<string>()
.Title(title)
.AddChoices(labels));

return map[selected];
}

public Menu()
{
_consoleUI = new ConsoleUI();
_manageDrinksService = new ManageDrinksService();
_favouriteDrinkService = new FavouriteDrinkService();
}

public async Task Start()
{
var running = true;
while (running)
{
_consoleUI.ShowHeader();
var choice = PromptEnum<CategoryOptions>(
"Choose your operation",
("Drinks Menu", CategoryOptions.DrinksMenu),
("My Favourites", CategoryOptions.MyFavourites),
("Exit", CategoryOptions.Exit));

switch (choice)
{
case CategoryOptions.DrinksMenu:
await ManageDrinksAsync();
break;
case CategoryOptions.MyFavourites:
ManageMyFavourites();
break;
case CategoryOptions.Exit:
running = false;
_consoleUI.ShowGoodbye();
break;
}
}
}

private async Task ManageDrinksAsync()
{
var isSubMenu = true;
while (isSubMenu)
{
_consoleUI.ShowHeader();
var choice = PromptEnum<DrinksOptions>(
"Choose your operation",
("View All Categories", DrinksOptions.ViewAll),
("Search Drink", DrinksOptions.SearchDrinks),
("Go Back", DrinksOptions.Goback));

try
{
switch (choice)
{
case DrinksOptions.ViewAll:
await _manageDrinksService.ViewAllCategoriesAsync();
break;
case DrinksOptions.SearchDrinks:
await _manageDrinksService.SearchDrinksAsync();
break;
case DrinksOptions.Goback:
isSubMenu = false;
break;
}
}
catch (Exception ex)
{
_consoleUI.ShowError(ex.Message);
_consoleUI.Pause();
}
}
}

private void ManageMyFavourites()
{
var isSubMenu = true;
while (isSubMenu)
{
_consoleUI.ShowHeader();
var choice = PromptEnum<MyFavouritesOptions>(
"Choose your operation",
("View All Favourite Drinks", MyFavouritesOptions.ViewAll),
("Most Viewed Drink", MyFavouritesOptions.ViewCount),
("Go Back", MyFavouritesOptions.GoBack));

try
{
switch (choice)
{
case MyFavouritesOptions.ViewAll:
_favouriteDrinkService.ViewAllDrinks();
_consoleUI.Pause();
break;
case MyFavouritesOptions.ViewCount:
_favouriteDrinkService.DisplayMostViewedDrink();
_consoleUI.Pause();
break;
case MyFavouritesOptions.GoBack:
isSubMenu = false;
break;
}

AnsiConsole.Clear();
}
catch (Exception ex)
{
_consoleUI.ShowError(ex.Message);
_consoleUI.Pause();
}
}
}
}
}
29 changes: 29 additions & 0 deletions Sangeerths.DrinkExplorer/DrinkExplorer/DrinkExplorer.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

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

<ItemGroup>
<None Remove="appsettings.json" />
</ItemGroup>

<ItemGroup>
<Content Include="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="10.0.10" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.10" />
<PackageReference Include="Spectre.Console" Version="0.57.2" />
<PackageReference Include="Spectre.Console.ImageSharp" Version="0.57.2" />
</ItemGroup>

</Project>
16 changes: 16 additions & 0 deletions Sangeerths.DrinkExplorer/DrinkExplorer/Models/CategoryResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Text.Json.Serialization;

namespace DrinkExplorer.Models
{
public class CategoryResponse
{
[JsonPropertyName("drinks")]
public List<Category>? Drinks { get; set; }
}

public class Category
{
[JsonPropertyName("strCategory")]
public string? StrCategory { get; set; }
}
}
13 changes: 13 additions & 0 deletions Sangeerths.DrinkExplorer/DrinkExplorer/Models/Drink.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace DrinkExplorer.Models
{
public class Drink
{
public string? IdDrink { get; set; }
public string? StrDrink { get; set; }
public string? StrDrinkThumb { get; set; }
public string? StrCategory { get; set; }
public string? StrAlcoholic { get; set; }
public string? StrGlass { get; set; }
public string? StrInstructions { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace DrinkExplorer.Models
{
public class DrinkResponse
{
public List<Drink>? Drinks { get; set; }

}
}
11 changes: 11 additions & 0 deletions Sangeerths.DrinkExplorer/DrinkExplorer/Models/DrinkView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace DrinkExplorer.Models
{
public class DrinkView
{
public string DrinkId { get; set; } = string.Empty;

public string DrinkName { get; set; } = string.Empty;

public int ViewCount { get; set; }
}
}
4 changes: 4 additions & 0 deletions Sangeerths.DrinkExplorer/DrinkExplorer/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using DrinkExplorer.Controller;

Menu menu = new Menu();
await menu.Start();
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
using DrinkExplorer.Models;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Configuration;

namespace DrinkExplorer.Database
{
public class FavoriteDrinkRepository
{
private readonly string _connectionString;

public FavoriteDrinkRepository()
{
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();

_connectionString = configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException(
"Connection string 'DefaultConnection' not found in appsettings.json.");
}

public void InsertFavouriteDrink(Drink drink)
{
using var connection = new SqlConnection(_connectionString);
connection.Open();
using var command = new SqlCommand("INSERT INTO FavouriteDrinks (DrinkId, DrinkName, Category, Alcoholic, Glass, Instructions, DrinkImageUrl) VALUES (@IdDrink, @StrDrink, @StrCategory, @StrAlcoholic, @StrGlass, @StrInstructions, @StrDrinkThumb)", connection);
command.Parameters.AddWithValue("@IdDrink", drink.IdDrink);
command.Parameters.AddWithValue("@StrDrink", drink.StrDrink);
command.Parameters.AddWithValue("@StrCategory", drink.StrCategory);
command.Parameters.AddWithValue("@StrAlcoholic", drink.StrAlcoholic);
command.Parameters.AddWithValue("@StrGlass", drink.StrGlass);
command.Parameters.AddWithValue("@StrInstructions", drink.StrInstructions);
command.Parameters.AddWithValue("@StrDrinkThumb", drink.StrDrinkThumb);
command.ExecuteNonQuery();
}

public DrinkResponse ShowAllFavourites()
{
using var connection = new SqlConnection(_connectionString);
connection.Open();
using var command = new SqlCommand("SELECT * FROM FavouriteDrinks ORDER BY DrinkName", connection);
using var reader = command.ExecuteReader();
var favouriteDrinks = new DrinkResponse
{
Drinks = new List<Drink>()
};

while (reader.Read())
{
favouriteDrinks.Drinks.Add(new Drink
{
IdDrink = reader.GetString(1),
StrDrink = reader.GetString(2),
StrCategory = reader.IsDBNull(3) ? null : reader.GetString(3),
StrAlcoholic = reader.IsDBNull(4) ? null : reader.GetString(4),
StrGlass = reader.IsDBNull(5) ? null : reader.GetString(5),
StrInstructions = reader.IsDBNull(6) ? null : reader.GetString(6),
StrDrinkThumb = reader.IsDBNull(7) ? null : reader.GetString(7)
});
}
return favouriteDrinks;
}

public void IncrementViewCount(Drink drink)
{
using var connection = new SqlConnection(_connectionString);
connection.Open();
const string query = """
IF EXISTS
(SELECT 1 FROM DrinkViews WHERE DrinkId = @DrinkId)
BEGIN
UPDATE DrinkViews SET ViewCount = ViewCount + 1 WHERE DrinkId = @DrinkId
END
ELSE
BEGIN
INSERT INTO DrinkViews (DrinkId, DrinkName, ViewCount ) VALUES( @DrinkId, @DrinkName, 1)
END
""";

using var command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@DrinkId",drink.IdDrink);
command.Parameters.AddWithValue("@DrinkName", drink.StrDrink);
command.ExecuteNonQuery();
}

public List<DrinkView> GetMostViewedDrinks()
{
using var connection = new SqlConnection(_connectionString);
connection.Open();
using var command = new SqlCommand("SELECT * FROM DrinkViews ORDER BY ViewCount DESC", connection);
using var reader = command.ExecuteReader();
var mostViewedDrinks = new List<DrinkView>();

while (reader.Read())
{
mostViewedDrinks.Add(new DrinkView
{
DrinkId = reader.GetString(0),
DrinkName = reader.GetString(1),
ViewCount = reader.GetInt32(2)
});
}
return mostViewedDrinks;
}
}
}
Loading