diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 353a3f0..310ffca 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -33,5 +33,6 @@ ], "deny": [], "ask": [] - } + }, + "outputStyle": "enterprise-full-stack-developer" } \ No newline at end of file diff --git a/CreateMultiBuysTable.cs b/CreateMultiBuysTable.cs new file mode 100644 index 0000000..652f581 --- /dev/null +++ b/CreateMultiBuysTable.cs @@ -0,0 +1,53 @@ +using Microsoft.Data.Sqlite; +using System; + +class Program +{ + static void Main() + { + var connectionString = "Data Source=C:\\Production\\Source\\LittleShop\\LittleShop\\littleshop.db"; + + using (var connection = new SqliteConnection(connectionString)) + { + connection.Open(); + + var createTableSql = @" + CREATE TABLE IF NOT EXISTS ProductMultiBuys ( + Id TEXT PRIMARY KEY NOT NULL, + ProductId TEXT NOT NULL, + Name TEXT NOT NULL, + Description TEXT NOT NULL DEFAULT '', + Quantity INTEGER NOT NULL, + Price REAL NOT NULL, + PricePerUnit REAL NOT NULL, + SortOrder INTEGER NOT NULL DEFAULT 0, + IsActive INTEGER NOT NULL DEFAULT 1, + CreatedAt TEXT NOT NULL, + UpdatedAt TEXT NOT NULL, + FOREIGN KEY (ProductId) REFERENCES Products(Id) ON DELETE CASCADE + )"; + + using (var command = new SqliteCommand(createTableSql, connection)) + { + command.ExecuteNonQuery(); + Console.WriteLine("ProductMultiBuys table created successfully!"); + } + + // Create indexes + var createIndexSql1 = "CREATE INDEX IF NOT EXISTS IX_ProductMultiBuys_ProductId ON ProductMultiBuys(ProductId)"; + var createIndexSql2 = "CREATE INDEX IF NOT EXISTS IX_ProductMultiBuys_IsActive ON ProductMultiBuys(IsActive)"; + + using (var command = new SqliteCommand(createIndexSql1, connection)) + { + command.ExecuteNonQuery(); + } + + using (var command = new SqliteCommand(createIndexSql2, connection)) + { + command.ExecuteNonQuery(); + } + + Console.WriteLine("Indexes created successfully!"); + } + } +} \ No newline at end of file diff --git a/LittleShop-Production-20250920-205012.tar.gz b/LittleShop-Production-20250920-205012.tar.gz new file mode 100644 index 0000000..1e572c6 Binary files /dev/null and b/LittleShop-Production-20250920-205012.tar.gz differ diff --git a/LittleShop-Production-20250920-210823.tar.gz b/LittleShop-Production-20250920-210823.tar.gz new file mode 100644 index 0000000..d415bf3 Binary files /dev/null and b/LittleShop-Production-20250920-210823.tar.gz differ diff --git a/LittleShop.Client/Services/CatalogService.cs b/LittleShop.Client/Services/CatalogService.cs index 9e8c011..0640315 100644 --- a/LittleShop.Client/Services/CatalogService.cs +++ b/LittleShop.Client/Services/CatalogService.cs @@ -116,14 +116,14 @@ public class CatalogService : ICatalogService try { var response = await _httpClient.GetAsync($"api/catalog/products/{id}"); - + if (response.IsSuccessStatusCode) { var product = await response.Content.ReadFromJsonAsync(); if (product != null) return ApiResponse.Success(product); } - + var error = await response.Content.ReadAsStringAsync(); return ApiResponse.Failure(error, response.StatusCode); } @@ -131,7 +131,31 @@ public class CatalogService : ICatalogService { _logger.LogError(ex, "Failed to get product {ProductId}", id); return ApiResponse.Failure( - ex.Message, + ex.Message, + System.Net.HttpStatusCode.InternalServerError); + } + } + + public async Task>> GetAvailableCurrenciesAsync() + { + try + { + var response = await _httpClient.GetAsync("api/currency/available"); + + if (response.IsSuccessStatusCode) + { + var currencies = await response.Content.ReadFromJsonAsync>(); + return ApiResponse>.Success(currencies ?? new List()); + } + + var error = await response.Content.ReadAsStringAsync(); + return ApiResponse>.Failure(error, response.StatusCode); + } + catch (Exception ex) + { + _logger.LogError(ex, "Failed to get available currencies"); + return ApiResponse>.Failure( + ex.Message, System.Net.HttpStatusCode.InternalServerError); } } diff --git a/LittleShop.Client/Services/ICatalogService.cs b/LittleShop.Client/Services/ICatalogService.cs index 7dea45a..61a8ccf 100644 --- a/LittleShop.Client/Services/ICatalogService.cs +++ b/LittleShop.Client/Services/ICatalogService.cs @@ -7,11 +7,12 @@ public interface ICatalogService Task>> GetCategoriesAsync(); Task> GetCategoryByIdAsync(Guid id); Task>> GetProductsAsync( - int pageNumber = 1, - int pageSize = 20, + int pageNumber = 1, + int pageSize = 20, Guid? categoryId = null, string? searchTerm = null, decimal? minPrice = null, decimal? maxPrice = null); Task> GetProductByIdAsync(Guid id); + Task>> GetAvailableCurrenciesAsync(); } \ No newline at end of file diff --git a/LittleShop/AddMultiBuysTable.csx b/LittleShop/AddMultiBuysTable.csx new file mode 100644 index 0000000..8cea3cf --- /dev/null +++ b/LittleShop/AddMultiBuysTable.csx @@ -0,0 +1,32 @@ +#r "nuget: Microsoft.Data.Sqlite, 9.0.1" + +using Microsoft.Data.Sqlite; + +var connectionString = @"Data Source=C:\Production\Source\LittleShop\LittleShop\littleshop.db"; + +using (var connection = new SqliteConnection(connectionString)) +{ + connection.Open(); + + var sql = @" + CREATE TABLE IF NOT EXISTS ProductMultiBuys ( + Id TEXT PRIMARY KEY NOT NULL, + ProductId TEXT NOT NULL, + Name TEXT NOT NULL, + Description TEXT NOT NULL DEFAULT '', + Quantity INTEGER NOT NULL, + Price REAL NOT NULL, + PricePerUnit REAL NOT NULL, + SortOrder INTEGER NOT NULL DEFAULT 0, + IsActive INTEGER NOT NULL DEFAULT 1, + CreatedAt TEXT NOT NULL, + UpdatedAt TEXT NOT NULL, + FOREIGN KEY (ProductId) REFERENCES Products(Id) ON DELETE CASCADE + )"; + + using (var command = new SqliteCommand(sql, connection)) + { + command.ExecuteNonQuery(); + Console.WriteLine("ProductMultiBuys table created successfully!"); + } +} \ No newline at end of file diff --git a/LittleShop/Areas/Admin/Controllers/SystemSettingsController.cs b/LittleShop/Areas/Admin/Controllers/SystemSettingsController.cs new file mode 100644 index 0000000..af41f72 --- /dev/null +++ b/LittleShop/Areas/Admin/Controllers/SystemSettingsController.cs @@ -0,0 +1,75 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using LittleShop.Services; +using LittleShop.Enums; + +namespace LittleShop.Areas.Admin.Controllers; + +[Area("Admin")] +[Authorize(Policy = "AdminOnly")] +public class SystemSettingsController : Controller +{ + private readonly ISystemSettingsService _systemSettingsService; + private readonly ILogger _logger; + + public SystemSettingsController( + ISystemSettingsService systemSettingsService, + ILogger logger) + { + _systemSettingsService = systemSettingsService; + _logger = logger; + } + + public async Task Index() + { + try + { + var viewModel = new SystemSettingsViewModel + { + TestCurrencies = new Dictionary + { + { "TBTC", await _systemSettingsService.IsTestCurrencyEnabledAsync("TBTC") }, + { "TLTC", await _systemSettingsService.IsTestCurrencyEnabledAsync("TLTC") } + } + }; + + return View(viewModel); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error loading system settings"); + ViewBag.Error = "Failed to load system settings"; + return View(new SystemSettingsViewModel()); + } + } + + [HttpPost] + public async Task UpdateTestCurrencies(SystemSettingsViewModel model) + { + try + { + if (model.TestCurrencies != null) + { + foreach (var currency in model.TestCurrencies) + { + await _systemSettingsService.SetTestCurrencyEnabledAsync(currency.Key, currency.Value); + _logger.LogInformation("Updated test currency {Currency} to {Enabled}", currency.Key, currency.Value); + } + } + + ViewBag.Success = "Test currency settings updated successfully"; + return View("Index", model); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error updating test currency settings"); + ViewBag.Error = "Failed to update test currency settings"; + return View("Index", model); + } + } +} + +public class SystemSettingsViewModel +{ + public Dictionary TestCurrencies { get; set; } = new(); +} \ No newline at end of file diff --git a/LittleShop/Areas/Admin/Views/Shared/_Layout.cshtml b/LittleShop/Areas/Admin/Views/Shared/_Layout.cshtml index 33e3ca7..e67343f 100644 --- a/LittleShop/Areas/Admin/Views/Shared/_Layout.cshtml +++ b/LittleShop/Areas/Admin/Views/Shared/_Layout.cshtml @@ -92,6 +92,11 @@ Bots +