diff --git a/Moonlight/App/Services/Store/StoreOrderService.cs b/Moonlight/App/Services/Store/StoreOrderService.cs index 95c6f4b4..a222ee30 100644 --- a/Moonlight/App/Services/Store/StoreOrderService.cs +++ b/Moonlight/App/Services/Store/StoreOrderService.cs @@ -141,4 +141,58 @@ public class StoreOrderService return await serviceService.Admin.Create(u, p, service => { service.RenewAt = DateTime.UtcNow.AddDays(duration); }); } + + public Task ValidateRenew(User u, Service s, int durationMultiplier) + { + using var scope = ServiceScopeFactory.CreateScope(); + var userRepo = scope.ServiceProvider.GetRequiredService>(); + var serviceRepo = scope.ServiceProvider.GetRequiredService>(); + + var user = userRepo.Get().FirstOrDefault(x => x.Id == u.Id); + + if(user == null) + throw new DisplayException("Unsafe value detected. Please reload the page to proceed"); + + var service = serviceRepo + .Get() + .Include(x => x.Product) + .Include(x => x.Owner) + .FirstOrDefault(x => x.Id == s.Id); + + if(service == null) + throw new DisplayException("Unsafe value detected. Please reload the page to proceed"); + + var price = service.Product.Price * durationMultiplier; + + if (user.Balance < price) + throw new DisplayException("Order is too expensive"); + + return Task.CompletedTask; + } + + public async Task Renew(User u, Service s, int durationMultiplier) + { + await ValidateRenew(u, s, durationMultiplier); + + using var scope = ServiceScopeFactory.CreateScope(); + var serviceRepo = scope.ServiceProvider.GetRequiredService>(); + var transactionService = scope.ServiceProvider.GetRequiredService(); + + var service = serviceRepo + .Get() + .Include(x => x.Product) + .Include(x => x.Owner) + .First(x => x.Id == s.Id); + + var price = service.Product.Price * durationMultiplier; + + // Calculate duration + var duration = durationMultiplier * service.Product.Duration; + + // Add transaction + await transactionService.Add(u, -1 * price, $"Renewed service '{service.Nickname ?? $"Service {service.Id}"}' for {duration} days"); + + service.RenewAt = service.RenewAt.AddDays(duration); + serviceRepo.Update(service); + } } \ No newline at end of file diff --git a/Moonlight/App/Services/Store/TransactionService.cs b/Moonlight/App/Services/Store/TransactionService.cs index 78536627..27c78f80 100644 --- a/Moonlight/App/Services/Store/TransactionService.cs +++ b/Moonlight/App/Services/Store/TransactionService.cs @@ -1,5 +1,6 @@ using Moonlight.App.Database.Entities; using Moonlight.App.Database.Entities.Store; +using Moonlight.App.Helpers; using Moonlight.App.Repositories; namespace Moonlight.App.Services.Store; @@ -28,6 +29,8 @@ public class TransactionService // We divide the call to ensure the transaction can be written to the database user.Balance += amount; + user.Balance = Math.Round(user.Balance, 2); // To prevent weird numbers + UserRepository.Update(user); return Task.CompletedTask; diff --git a/Moonlight/Shared/Components/Modals/ManageServiceShareModal.razor b/Moonlight/Shared/Components/Modals/ManageServiceShareModal.razor index 7c25bc50..693bcd54 100644 --- a/Moonlight/Shared/Components/Modals/ManageServiceShareModal.razor +++ b/Moonlight/Shared/Components/Modals/ManageServiceShareModal.razor @@ -7,7 +7,7 @@ - - + + } @@ -78,19 +173,74 @@ else { [Parameter] public Service Service { get; set; } - + [Parameter] public Func OnChange { get; set; } private bool ShowDeletionScreen = false; + private bool ShowRenewScreen = false; private ManageServiceShareModal ShareModal; + private int DurationMultiplier = 1; + private bool CanBeRenewed = false; + private bool IsValidating = false; + private string ErrorMessage = ""; + + private Task Revalidate() + { + IsValidating = true; + InvokeAsync(StateHasChanged); + + Task.Run(async () => + { + try + { + await StoreService.Order.ValidateRenew(IdentityService.CurrentUser, Service, DurationMultiplier); + CanBeRenewed = true; + } + catch (DisplayException e) + { + CanBeRenewed = false; + ErrorMessage = e.Message; + } + + IsValidating = false; + await InvokeAsync(StateHasChanged); + }); + + return Task.CompletedTask; + } + + private async Task Renew() + { + await StoreService.Order.Renew(IdentityService.CurrentUser, Service, DurationMultiplier); + + await ToastService.Success("Successfully renewed service"); + await OnChange.Invoke(); + } + + private async Task SetDurationMultiplier(int i) + { + DurationMultiplier = i; + await Revalidate(); + } + private async Task SetShowDeletion(bool b) { ShowDeletionScreen = b; await InvokeAsync(StateHasChanged); } - + + private async Task SetShowRenew(bool b) + { + ShowRenewScreen = b; + + if (b) // Revalidate when the renew screen is shown + await Revalidate(); + + await InvokeAsync(StateHasChanged); + } + public async Task Delete() { await ServiceService.Admin.Delete(Service); @@ -98,4 +248,4 @@ else await ToastService.Success("Successfully deleted service"); await OnChange.Invoke(); } -} +} \ No newline at end of file diff --git a/Moonlight/Shared/Views/Store/Order.razor b/Moonlight/Shared/Views/Store/Order.razor index 1d2ff67f..a21da6e5 100644 --- a/Moonlight/Shared/Views/Store/Order.razor +++ b/Moonlight/Shared/Views/Store/Order.razor @@ -36,17 +36,17 @@ TODO: Add 404 here @{ - var defaultPrice = SelectedProduct.Price * DurationMultiplicator; + var defaultPrice = SelectedProduct.Price * DurationMultiplier; double actualPrice; if (SelectedCoupon == null) @@ -90,13 +90,13 @@ TODO: Add 404 here
Renew
- @(currency) @(defaultPrice) + @(currency) @(SelectedProduct.Price)
Duration
- @(SelectedProduct.Duration * DurationMultiplicator) days + @(SelectedProduct.Duration * DurationMultiplier) days
@@ -161,7 +161,7 @@ TODO: Add 404 here private Product? SelectedProduct; private Coupon? SelectedCoupon; - private int DurationMultiplicator = 1; + private int DurationMultiplier = 1; private string CouponCode = ""; @@ -169,9 +169,9 @@ TODO: Add 404 here private bool IsValidating = false; private string ErrorMessage = ""; - private async Task SetDurationMultiplicator(int i) + private async Task SetDurationMultiplier(int i) { - DurationMultiplicator = i; + DurationMultiplier = i; await Revalidate(); } @@ -206,7 +206,7 @@ TODO: Add 404 here { try { - await StoreService.Order.Validate(IdentityService.CurrentUser, SelectedProduct, 1, SelectedCoupon); + await StoreService.Order.Validate(IdentityService.CurrentUser, SelectedProduct, DurationMultiplier, SelectedCoupon); CanBeOrdered = true; } catch (DisplayException e) @@ -242,7 +242,7 @@ TODO: Add 404 here .Process( IdentityService.CurrentUser, SelectedProduct, - DurationMultiplicator, + DurationMultiplier, SelectedCoupon );