diff --git a/LiteCharms.Features.MidrandBooks.Seed/LiteCharms.Features.MidrandBooks.Seed.csproj b/LiteCharms.Features.MidrandBooks.Seed/LiteCharms.Features.MidrandBooks.Seed.csproj
index 86652ed..aeaaf0b 100644
--- a/LiteCharms.Features.MidrandBooks.Seed/LiteCharms.Features.MidrandBooks.Seed.csproj
+++ b/LiteCharms.Features.MidrandBooks.Seed/LiteCharms.Features.MidrandBooks.Seed.csproj
@@ -16,7 +16,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
@@ -30,11 +30,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -47,9 +47,9 @@
-
-
-
+
+
+
@@ -58,12 +58,12 @@
-
-
+
+
-
+
@@ -75,13 +75,13 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -116,8 +116,8 @@
-
-
+
+
diff --git a/LiteCharms.Features.MidrandBooks/LiteCharms.Features.MidrandBooks.csproj b/LiteCharms.Features.MidrandBooks/LiteCharms.Features.MidrandBooks.csproj
index a8bef3a..c2f0ac7 100644
--- a/LiteCharms.Features.MidrandBooks/LiteCharms.Features.MidrandBooks.csproj
+++ b/LiteCharms.Features.MidrandBooks/LiteCharms.Features.MidrandBooks.csproj
@@ -36,7 +36,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
@@ -50,11 +50,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -67,9 +67,9 @@
-
-
-
+
+
+
@@ -78,12 +78,12 @@
-
-
+
+
-
+
@@ -95,13 +95,13 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -136,8 +136,8 @@
-
-
+
+
diff --git a/LiteCharms.Features.MidrandBooks/Payments/CartService.cs b/LiteCharms.Features.MidrandBooks/Payments/CartService.cs
new file mode 100644
index 0000000..64d55bd
--- /dev/null
+++ b/LiteCharms.Features.MidrandBooks/Payments/CartService.cs
@@ -0,0 +1,154 @@
+using LiteCharms.Features.Abstractions;
+using LiteCharms.Features.Browser;
+using LiteCharms.Features.Hasher;
+using LiteCharms.Features.MidrandBooks.Authors.Models;
+using LiteCharms.Features.MidrandBooks.Payments.Models;
+using LiteCharms.Features.MidrandBooks.Products.Models;
+
+namespace LiteCharms.Features.MidrandBooks.Payments;
+
+public sealed class CartService(LocalStorageService localStorage) : IService
+{
+ private readonly string CartStorageKey = HashService.ToMd5Hash(nameof(Cart)).Value;
+
+ public Cart ShoppingCart { get; private set; } = new();
+
+ public event Action? OnCartChanged;
+
+ public static Func GetCartItemQuantity = (shoppingCart, productPriceId) =>
+ shoppingCart.Items.FirstOrDefault(p => p.Price!.Id == productPriceId)?.Quantity ?? 1;
+
+ public Cart GetCart() => ShoppingCart;
+
+ public void NotifyStateChanged() => OnCartChanged?.Invoke();
+
+ public async Task LoadCartFromStorageAsync()
+ {
+ var loadResult = await localStorage.GetAsync(CartStorageKey);
+
+ if (loadResult.IsFailed) await localStorage.SaveAsync(CartStorageKey, ShoppingCart);
+
+ if (loadResult.IsSuccess) ShoppingCart = loadResult.Value;
+
+ NotifyStateChanged();
+ }
+
+ public async Task SaveCartToStorageAsync() => await localStorage.SaveAsync(CartStorageKey, ShoppingCart);
+
+ public void AddItem(ProductPrice productPrice, Product product, Author author)
+ {
+ var itemExists = false;
+
+ for (var i = 0; i < ShoppingCart.Items.Count; i++)
+ {
+ if (ShoppingCart.Items[i].Price!.Id == productPrice.Id)
+ {
+ ShoppingCart.Items[i].Quantity++;
+ ShoppingCart.Items[i].Amount += productPrice.Amount;
+
+ itemExists = true;
+
+ break;
+ }
+ }
+
+ if (!itemExists)
+ ShoppingCart.Items.Add(new CartItem
+ {
+ Product = product,
+ Author = author,
+ Price = productPrice,
+ Amount = productPrice.Amount,
+ Quantity = 1,
+ });
+
+ CalculateTotalPrice();
+ NotifyStateChanged();
+ }
+
+ public void UpdateQuantity(long productPriceId, int delta)
+ {
+ for (var i = 0; i < ShoppingCart.Items.Count; i++)
+ {
+ if (ShoppingCart.Items[i].Price!.Id == productPriceId)
+ {
+ var oldQuantity = ShoppingCart.Items[i].Quantity;
+ var pricePerUnit = ShoppingCart.Items[i].Price!.Amount;
+
+ ShoppingCart.Items[i].Quantity += delta;
+ ShoppingCart.Items[i].Amount = pricePerUnit * ShoppingCart.Items[i].Quantity;
+ break;
+ }
+ }
+
+ CalculateTotalPrice();
+ NotifyStateChanged();
+ }
+
+ public void RemoveOneItem(long productPriceId)
+ {
+ for (var i = 0; i < ShoppingCart.Items.Count; i++)
+ {
+ if (ShoppingCart.Items[i].Price!.Id == productPriceId)
+ {
+ if (ShoppingCart.Items[i].Quantity <= 1)
+ {
+ ShoppingCart.Items.Remove(ShoppingCart.Items[i]);
+
+ break;
+ }
+ else
+ {
+ ShoppingCart.Items[i].Quantity--;
+ ShoppingCart.Items[i].Amount -= ShoppingCart.Items[i].Price!.Amount;
+ }
+
+ break;
+ }
+ }
+
+ CalculateTotalPrice();
+ NotifyStateChanged();
+ }
+
+ public void RemoveAllSameItem(long productPriceId)
+ {
+ if (ShoppingCart.Items.Count == 0) return;
+
+ var item = ShoppingCart.Items.FirstOrDefault(i => i.Price?.Id == productPriceId);
+
+ if (item is not null) ShoppingCart.Items.Remove(item);
+
+ CalculateTotalPrice();
+ NotifyStateChanged();
+ }
+
+ public void Clear()
+ {
+ if(ShoppingCart.CustomerId is not null || ShoppingCart.OrderId is not null)
+ {
+ ShoppingCart.TotalAmount = 0;
+ ShoppingCart.TotalVat = 0;
+ ShoppingCart.Items.Clear();
+
+ return;
+ }
+
+ ShoppingCart = new Cart();
+
+ NotifyStateChanged();
+ }
+
+ public decimal CalculateTotalPrice()
+ {
+ if (ShoppingCart.Items.Count == 0) return 0;
+
+ var gross = ShoppingCart.Items.Sum(i => i.Amount);
+
+ if (!ShoppingCart.IsVatInclusive) ShoppingCart.TotalVat = gross * ShoppingCart.VatRate;
+
+ ShoppingCart.TotalAmount = gross + ShoppingCart.TotalVat;
+
+ return ShoppingCart.TotalAmount;
+ }
+}
diff --git a/LiteCharms.Features.MidrandBooks/Payments/Models/Cart.cs b/LiteCharms.Features.MidrandBooks/Payments/Models/Cart.cs
new file mode 100644
index 0000000..3af0292
--- /dev/null
+++ b/LiteCharms.Features.MidrandBooks/Payments/Models/Cart.cs
@@ -0,0 +1,18 @@
+namespace LiteCharms.Features.MidrandBooks.Payments.Models;
+
+public sealed class Cart
+{
+ public long? CustomerId { get; set; }
+
+ public long? OrderId { get; set; }
+
+ public decimal TotalAmount { get; set; }
+
+ public decimal TotalVat { get; set; }
+
+ public decimal VatRate { get; set; } = 0.15m;
+
+ public bool IsVatInclusive { get; set; } = true;
+
+ public IList Items { get; set; } = [];
+}
diff --git a/LiteCharms.Features.MidrandBooks/Payments/Models/CartItem.cs b/LiteCharms.Features.MidrandBooks/Payments/Models/CartItem.cs
new file mode 100644
index 0000000..a656420
--- /dev/null
+++ b/LiteCharms.Features.MidrandBooks/Payments/Models/CartItem.cs
@@ -0,0 +1,17 @@
+using LiteCharms.Features.MidrandBooks.Authors.Models;
+using LiteCharms.Features.MidrandBooks.Products.Models;
+
+namespace LiteCharms.Features.MidrandBooks.Payments.Models;
+
+public sealed class CartItem
+{
+ public Author? Author { get; set; }
+
+ public Product? Product { get; set; }
+
+ public ProductPrice? Price { get; set; }
+
+ public int Quantity { get; set; }
+
+ public decimal Amount { get; set; }
+}
diff --git a/LiteCharms.Features.TechShop/LiteCharms.Features.TechShop.csproj b/LiteCharms.Features.TechShop/LiteCharms.Features.TechShop.csproj
index 5f01765..2b3ad94 100644
--- a/LiteCharms.Features.TechShop/LiteCharms.Features.TechShop.csproj
+++ b/LiteCharms.Features.TechShop/LiteCharms.Features.TechShop.csproj
@@ -36,7 +36,7 @@
-
+
@@ -50,11 +50,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -67,9 +67,9 @@
-
-
-
+
+
+
@@ -78,12 +78,12 @@
-
-
+
+
-
+
@@ -95,13 +95,13 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -136,8 +136,8 @@
-
-
+
+
diff --git a/LiteCharms.Features/LiteCharms.Features.csproj b/LiteCharms.Features/LiteCharms.Features.csproj
index fc6cc2f..b2374c2 100644
--- a/LiteCharms.Features/LiteCharms.Features.csproj
+++ b/LiteCharms.Features/LiteCharms.Features.csproj
@@ -35,8 +35,8 @@
-
-
+
+
@@ -56,8 +56,8 @@
-
-
+
+
@@ -71,7 +71,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
@@ -85,11 +85,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -102,9 +102,9 @@
-
-
-
+
+
+
@@ -113,12 +113,12 @@
-
-
+
+
-
+
@@ -130,13 +130,13 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -171,8 +171,8 @@
-
-
+
+