Refactored some forms. Added service shares
This commit is contained in:
parent
48c95d4ec6
commit
3d4f22f6f6
21 changed files with 347 additions and 50 deletions
|
@ -1,6 +1,6 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.App.Models.Forms;
|
namespace Moonlight.App.Models.Forms.Admin.Users;
|
||||||
|
|
||||||
public class UpdateUserForm
|
public class UpdateUserForm
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.App.Models.Forms;
|
namespace Moonlight.App.Models.Forms.Admin.Users;
|
||||||
|
|
||||||
public class UpdateUserPasswordForm
|
public class UpdateUserPasswordForm
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.App.Models.Forms;
|
namespace Moonlight.App.Models.Forms.Auth;
|
||||||
|
|
||||||
public class LoginForm
|
public class LoginForm
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.App.Models.Forms;
|
namespace Moonlight.App.Models.Forms.Auth;
|
||||||
|
|
||||||
public class RegisterForm
|
public class RegisterForm
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.App.Models.Forms;
|
namespace Moonlight.App.Models.Forms.Auth;
|
||||||
|
|
||||||
public class ResetPasswordForm
|
public class ResetPasswordForm
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.App.Models.Forms;
|
namespace Moonlight.App.Models.Forms.Auth;
|
||||||
|
|
||||||
public class TwoFactorCodeForm
|
public class TwoFactorCodeForm
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.App.Models.Forms;
|
namespace Moonlight.App.Models.Forms.Auth;
|
||||||
|
|
||||||
public class UpdateAccountForm
|
public class UpdateAccountForm
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
namespace Moonlight.App.Models.Forms;
|
namespace Moonlight.App.Models.Forms.Auth;
|
||||||
|
|
||||||
public class UpdateAccountPasswordForm
|
public class UpdateAccountPasswordForm
|
||||||
{
|
{
|
13
Moonlight/App/Models/Forms/Services/AddUserToServiceForm.cs
Normal file
13
Moonlight/App/Models/Forms/Services/AddUserToServiceForm.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms.Services;
|
||||||
|
|
||||||
|
public class AddUserToServiceForm
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "You need to provide an username")]
|
||||||
|
[MinLength(7, ErrorMessage = "The username is too short")]
|
||||||
|
[MaxLength(20, ErrorMessage = "The username cannot be longer than 20 characters")]
|
||||||
|
[RegularExpression("^[a-z][a-z0-9]*$",
|
||||||
|
ErrorMessage = "Usernames can only contain lowercase characters and numbers")]
|
||||||
|
public string Username { get; set; } = "";
|
||||||
|
}
|
|
@ -55,6 +55,34 @@ public class ServiceAdminService
|
||||||
return finishedService;
|
return finishedService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task Delete(Service s)
|
||||||
|
{
|
||||||
|
using var scope = ServiceScopeFactory.CreateScope();
|
||||||
|
var serviceRepo = scope.ServiceProvider.GetRequiredService<Repository<Service>>();
|
||||||
|
var serviceShareRepo = scope.ServiceProvider.GetRequiredService<Repository<ServiceShare>>();
|
||||||
|
|
||||||
|
var service = serviceRepo
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.Product)
|
||||||
|
.Include(x => x.Shares)
|
||||||
|
.FirstOrDefault(x => x.Id == s.Id);
|
||||||
|
|
||||||
|
if (service == null)
|
||||||
|
throw new DisplayException("Service does not exist anymore");
|
||||||
|
|
||||||
|
if (!Actions.ContainsKey(service.Product.Type))
|
||||||
|
throw new DisplayException($"The product type {service.Product.Type} is not registered");
|
||||||
|
|
||||||
|
await Actions[service.Product.Type].Delete(scope.ServiceProvider, service);
|
||||||
|
|
||||||
|
foreach (var share in service.Shares)
|
||||||
|
{
|
||||||
|
serviceShareRepo.Delete(share);
|
||||||
|
}
|
||||||
|
|
||||||
|
serviceRepo.Delete(service);
|
||||||
|
}
|
||||||
|
|
||||||
public Task RegisterAction(ServiceType type, ServiceActions actions) // Use this function to register service types
|
public Task RegisterAction(ServiceType type, ServiceActions actions) // Use this function to register service types
|
||||||
{
|
{
|
||||||
Actions.Add(type, actions);
|
Actions.Add(type, actions);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Moonlight.App.Database.Entities;
|
using Moonlight.App.Database.Entities;
|
||||||
using Moonlight.App.Database.Entities.Store;
|
using Moonlight.App.Database.Entities.Store;
|
||||||
|
using Moonlight.App.Exceptions;
|
||||||
using Moonlight.App.Repositories;
|
using Moonlight.App.Repositories;
|
||||||
|
|
||||||
namespace Moonlight.App.Services.ServiceManage;
|
namespace Moonlight.App.Services.ServiceManage;
|
||||||
|
@ -9,13 +10,15 @@ public class ServiceService // This service is used for managing services and cr
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider ServiceProvider;
|
private readonly IServiceProvider ServiceProvider;
|
||||||
private readonly Repository<Service> ServiceRepository;
|
private readonly Repository<Service> ServiceRepository;
|
||||||
|
private readonly Repository<User> UserRepository;
|
||||||
|
|
||||||
public ServiceAdminService Admin => ServiceProvider.GetRequiredService<ServiceAdminService>();
|
public ServiceAdminService Admin => ServiceProvider.GetRequiredService<ServiceAdminService>();
|
||||||
|
|
||||||
public ServiceService(IServiceProvider serviceProvider, Repository<Service> serviceRepository)
|
public ServiceService(IServiceProvider serviceProvider, Repository<Service> serviceRepository, Repository<User> userRepository)
|
||||||
{
|
{
|
||||||
ServiceProvider = serviceProvider;
|
ServiceProvider = serviceProvider;
|
||||||
ServiceRepository = serviceRepository;
|
ServiceRepository = serviceRepository;
|
||||||
|
UserRepository = userRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<Service[]> Get(User user)
|
public Task<Service[]> Get(User user)
|
||||||
|
@ -40,4 +43,70 @@ public class ServiceService // This service is used for managing services and cr
|
||||||
|
|
||||||
return Task.FromResult(result);
|
return Task.FromResult(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task AddSharedUser(Service s, string username)
|
||||||
|
{
|
||||||
|
var userToAdd = UserRepository
|
||||||
|
.Get()
|
||||||
|
.FirstOrDefault(x => x.Username == username);
|
||||||
|
|
||||||
|
if (userToAdd == null)
|
||||||
|
throw new DisplayException("No user found with this username");
|
||||||
|
|
||||||
|
var service = ServiceRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.Owner)
|
||||||
|
.Include(x => x.Shares)
|
||||||
|
.ThenInclude(x => x.User)
|
||||||
|
.First(x => x.Id == s.Id);
|
||||||
|
|
||||||
|
if (service.Owner.Id == userToAdd.Id)
|
||||||
|
throw new DisplayException("The owner cannot be added as a shared user");
|
||||||
|
|
||||||
|
if (service.Shares.Any(x => x.User.Id == userToAdd.Id))
|
||||||
|
throw new DisplayException("The user has already access to this service");
|
||||||
|
|
||||||
|
service.Shares.Add(new ()
|
||||||
|
{
|
||||||
|
User = userToAdd
|
||||||
|
});
|
||||||
|
|
||||||
|
ServiceRepository.Update(service);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<User[]> GetSharedUsers(Service s)
|
||||||
|
{
|
||||||
|
var service = ServiceRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.Shares)
|
||||||
|
.ThenInclude(x => x.User)
|
||||||
|
.First(x => x.Id == s.Id);
|
||||||
|
|
||||||
|
var result = service.Shares
|
||||||
|
.Select(x => x.User)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return Task.FromResult(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task RemoveSharedUser(Service s, User user)
|
||||||
|
{
|
||||||
|
var service = ServiceRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.Shares)
|
||||||
|
.ThenInclude(x => x.User)
|
||||||
|
.First(x => x.Id == s.Id);
|
||||||
|
|
||||||
|
var shareToRemove = service.Shares.FirstOrDefault(x => x.User.Id == user.Id);
|
||||||
|
|
||||||
|
if (shareToRemove == null)
|
||||||
|
throw new DisplayException("This user does not have access to this service");
|
||||||
|
|
||||||
|
service.Shares.Remove(shareToRemove);
|
||||||
|
ServiceRepository.Update(service);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
@using Moonlight.App.Services.Users
|
@using Moonlight.App.Services.Users
|
||||||
@using Moonlight.App.Models.Forms
|
@using Moonlight.App.Models.Forms
|
||||||
@using Moonlight.App.Models.Enums
|
@using Moonlight.App.Models.Enums
|
||||||
|
@using Moonlight.App.Models.Forms.Auth
|
||||||
|
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject UserService UserService
|
@inject UserService UserService
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
@using Moonlight.App.Services
|
@using Moonlight.App.Services
|
||||||
@using Moonlight.App.Models.Forms
|
@using Moonlight.App.Models.Forms
|
||||||
|
@using Moonlight.App.Models.Forms.Auth
|
||||||
|
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject CookieService CookieService
|
@inject CookieService CookieService
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
@using Moonlight.App.Services.Users
|
@using Moonlight.App.Services.Users
|
||||||
@using Moonlight.App.Models.Forms
|
@using Moonlight.App.Models.Forms
|
||||||
|
@using Moonlight.App.Models.Forms.Auth
|
||||||
|
|
||||||
@inject UserService UserService
|
@inject UserService UserService
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
@using Moonlight.App.Models.Forms
|
@using Moonlight.App.Models.Forms
|
||||||
@using Moonlight.App.Services.Users
|
@using Moonlight.App.Services.Users
|
||||||
@using Moonlight.App.Exceptions
|
@using Moonlight.App.Exceptions
|
||||||
|
@using Moonlight.App.Models.Forms.Auth
|
||||||
|
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject UserService UserService
|
@inject UserService UserService
|
||||||
|
|
105
Moonlight/Shared/Components/Modals/ManageServiceShareModal.razor
Normal file
105
Moonlight/Shared/Components/Modals/ManageServiceShareModal.razor
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
@using Moonlight.App.Services.ServiceManage
|
||||||
|
@using Moonlight.App.Database.Entities.Store
|
||||||
|
@using BlazorTable
|
||||||
|
@using Moonlight.App.Models.Forms.Services
|
||||||
|
|
||||||
|
@inject ServiceService ServiceService
|
||||||
|
|
||||||
|
<SmartModal @ref="Modal" CssClasses="modal-dialog-centered modal-lg">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title">Manage shared users</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<LazyLoader @ref="LazyLoader" Load="Load">
|
||||||
|
<div class="mb-3">
|
||||||
|
<SmartForm Model="Form" OnValidSubmit="Add">
|
||||||
|
<div class="input-group">
|
||||||
|
<input @bind="Form.Username" type="text" placeholder="Enter a username..." class="form-control"/>
|
||||||
|
<button type="submit" class="btn btn-primary">Add</button>
|
||||||
|
</div>
|
||||||
|
</SmartForm>
|
||||||
|
</div>
|
||||||
|
@if (Users.Any())
|
||||||
|
{
|
||||||
|
<Table TableItem="User"
|
||||||
|
Items="Users"
|
||||||
|
PageSize="50"
|
||||||
|
TableClass="table table-row-bordered table-row-gray-100 align-middle gs-0 gy-3 fs-6"
|
||||||
|
TableHeadClass="fw-bold text-muted">
|
||||||
|
<Column TableItem="User" Title="" Field="@(x => x.Id)" Sortable="false" Filterable="false">
|
||||||
|
<Template>
|
||||||
|
<div class="symbol symbol-50px me-5">
|
||||||
|
@if (context.Avatar == null)
|
||||||
|
{
|
||||||
|
<img src="/assets/img/avatar.png" alt="Avatar">
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<img src="/api/bucket/avatars/@(context.Avatar)" alt="Avatar">
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<span class="ms-3">@(context.Username)</span>
|
||||||
|
</Template>
|
||||||
|
</Column>
|
||||||
|
<Column TableItem="User" Title="" Field="@(x => x.Id)" Sortable="false" Filterable="false">
|
||||||
|
<Template>
|
||||||
|
<div class="text-end me-3">
|
||||||
|
<a @onclick="() => Remove(context)" @onclick:preventDefault href="#" class="text-danger">Remove</a>
|
||||||
|
</div>
|
||||||
|
</Template>
|
||||||
|
</Column>
|
||||||
|
</Table>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="d-flex justify-content-center py-4">
|
||||||
|
<span class="mt-3 fs-5">No users found</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</LazyLoader>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</SmartModal>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public Service Service { get; set; }
|
||||||
|
|
||||||
|
private SmartModal Modal;
|
||||||
|
private LazyLoader LazyLoader;
|
||||||
|
private User[] Users;
|
||||||
|
|
||||||
|
private AddUserToServiceForm Form = new();
|
||||||
|
|
||||||
|
private async Task Load(LazyLoader _)
|
||||||
|
{
|
||||||
|
Users = await ServiceService.GetSharedUsers(Service);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Add()
|
||||||
|
{
|
||||||
|
await ServiceService.AddSharedUser(Service, Form.Username);
|
||||||
|
Form = new();
|
||||||
|
await LazyLoader.Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Remove(User user)
|
||||||
|
{
|
||||||
|
await ServiceService.RemoveSharedUser(Service, user);
|
||||||
|
await LazyLoader.Reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Show()
|
||||||
|
{
|
||||||
|
await Modal.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Hide()
|
||||||
|
{
|
||||||
|
await Modal.Hide();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,10 @@
|
||||||
<div class="modal fade" id="modal@(Id)" tabindex="-1">
|
<div class="modal fade" id="modal@(Id)" tabindex="-1">
|
||||||
<div class="modal-dialog @(CssClasses)">
|
<div class="modal-dialog @(CssClasses)">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@ChildContent
|
@if (ShouldShow)
|
||||||
|
{
|
||||||
|
@ChildContent
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -17,6 +20,7 @@
|
||||||
public RenderFragment ChildContent { get; set; }
|
public RenderFragment ChildContent { get; set; }
|
||||||
|
|
||||||
private int Id;
|
private int Id;
|
||||||
|
private bool ShouldShow = false;
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
|
@ -25,11 +29,17 @@
|
||||||
|
|
||||||
public async Task Show()
|
public async Task Show()
|
||||||
{
|
{
|
||||||
|
ShouldShow = true;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
|
||||||
await ModalService.Show("modal" + Id);
|
await ModalService.Show("modal" + Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Hide()
|
public async Task Hide()
|
||||||
{
|
{
|
||||||
await ModalService.Hide("modal" + Id);
|
await ModalService.Hide("modal" + Id);
|
||||||
|
|
||||||
|
ShouldShow = false;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
101
Moonlight/Shared/Components/Service/ServiceItem.razor
Normal file
101
Moonlight/Shared/Components/Service/ServiceItem.razor
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
@using Moonlight.App.Database.Entities.Store
|
||||||
|
@using Moonlight.App.Services
|
||||||
|
@using Moonlight.App.Services.ServiceManage
|
||||||
|
@using Moonlight.Shared.Components.Modals
|
||||||
|
|
||||||
|
@inject ConfigService ConfigService
|
||||||
|
@inject ToastService ToastService
|
||||||
|
@inject ServiceService ServiceService
|
||||||
|
|
||||||
|
@if (ShowDeletionScreen)
|
||||||
|
{
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title align-items-start flex-column">
|
||||||
|
<span class="card-label fw-bold text-dark fs-3">Do you really wan to delete @(Service.Nickname ?? $"Service {Service.Id}")</span>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p class="text-gray-400 fs-5 fw-semibold">
|
||||||
|
This action cannot be undone. Your service data will be deleted and cannot be restored
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer p-3">
|
||||||
|
<div class="btn-group w-100">
|
||||||
|
<WButton OnClick="Delete" Text="Delete" CssClasses="btn btn-danger w-50 me-3" />
|
||||||
|
<button @onclick="() => SetShowDeletion(false)" class="btn btn-secondary w-50">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h3 class="card-title align-items-start flex-column">
|
||||||
|
<span class="card-label fw-bold text-dark fs-3">@(Service.Nickname ?? $"Service {Service.Id}")</span>
|
||||||
|
<span class="text-gray-400 mt-1 fw-semibold fs-6">@(Service.Product.Name)</span>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-body fs-6">
|
||||||
|
<div class="d-flex flex-stack">
|
||||||
|
<div class="text-gray-700 fw-semibold me-2">Renew price</div>
|
||||||
|
<div class="d-flex align-items-senter">
|
||||||
|
<span class="fw-bold">@(ConfigService.Get().Store.Currency) @(Service.Product.Price)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex flex-stack">
|
||||||
|
<div class="text-gray-700 fw-semibold me-2">Renew at</div>
|
||||||
|
<div class="d-flex align-items-senter">
|
||||||
|
<span class="fw-bold">@(Formatter.FormatDate(Service.RenewAt))</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex flex-stack">
|
||||||
|
<div class="text-gray-700 fw-semibold me-2">Created at</div>
|
||||||
|
<div class="d-flex align-items-senter">
|
||||||
|
<span class="fw-bold">@(Formatter.FormatDate(Service.CreatedAt))</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer p-3">
|
||||||
|
<div class="btn-group w-100 mb-3">
|
||||||
|
<a href="/service/@(Service.Id)" class="btn btn-primary w-50 me-3">Manage</a>
|
||||||
|
<button @onclick="() => ShareModal.Show()" class="btn btn-secondary w-50">Manage shares</button>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group w-100">
|
||||||
|
<button class="btn btn-warning w-50 me-3">Renew</button>
|
||||||
|
<button @onclick="() => SetShowDeletion(true)" class="btn btn-danger w-50">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ManageServiceShareModal @ref="ShareModal" Service="Service" />
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public Service Service { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<Task> OnChange { get; set; }
|
||||||
|
|
||||||
|
private bool ShowDeletionScreen = false;
|
||||||
|
private ManageServiceShareModal ShareModal;
|
||||||
|
|
||||||
|
private async Task SetShowDeletion(bool b)
|
||||||
|
{
|
||||||
|
ShowDeletionScreen = b;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Delete()
|
||||||
|
{
|
||||||
|
await ServiceService.Admin.Delete(Service);
|
||||||
|
|
||||||
|
await ToastService.Success("Successfully deleted service");
|
||||||
|
await OnChange.Invoke();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
@using Moonlight.App.Services
|
@using Moonlight.App.Services
|
||||||
@using Moonlight.App.Services.Users
|
@using Moonlight.App.Services.Users
|
||||||
@using Moonlight.App.Models.Forms
|
@using Moonlight.App.Models.Forms
|
||||||
|
@using Moonlight.App.Models.Forms.Auth
|
||||||
|
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject UserService UserService
|
@inject UserService UserService
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
@using OtpNet
|
@using OtpNet
|
||||||
@using QRCoder
|
@using QRCoder
|
||||||
@using Moonlight.App.Models.Enums
|
@using Moonlight.App.Models.Enums
|
||||||
|
@using Moonlight.App.Models.Forms.Auth
|
||||||
|
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject UserService UserService
|
@inject UserService UserService
|
||||||
|
|
|
@ -3,54 +3,17 @@
|
||||||
@using Moonlight.App.Services.ServiceManage
|
@using Moonlight.App.Services.ServiceManage
|
||||||
@using Moonlight.App.Database.Entities.Store
|
@using Moonlight.App.Database.Entities.Store
|
||||||
@using Moonlight.App.Services
|
@using Moonlight.App.Services
|
||||||
|
@using Moonlight.Shared.Components.Service
|
||||||
|
|
||||||
@inject ServiceService ServiceService
|
@inject ServiceService ServiceService
|
||||||
@inject IdentityService IdentityService
|
@inject IdentityService IdentityService
|
||||||
@inject ConfigService ConfigService
|
|
||||||
|
|
||||||
<LazyLoader ShowAsCard="true" Load="Load">
|
<LazyLoader @ref="LazyLoader" ShowAsCard="true" Load="Load">
|
||||||
<div class="row mb-5">
|
<div class="row mb-5">
|
||||||
@foreach (var service in MyServices)
|
@foreach (var service in MyServices)
|
||||||
{
|
{
|
||||||
<div class="col-md-3 col-12">
|
<div class="col-md-3 col-12">
|
||||||
<div class="card">
|
<ServiceItem Service="service" OnChange="LazyLoader.Reload" />
|
||||||
<div class="card-header">
|
|
||||||
<h3 class="card-title align-items-start flex-column">
|
|
||||||
<span class="card-label fw-bold text-dark fs-3">@(service.Nickname ?? $"Service {service.Id}")</span>
|
|
||||||
<span class="text-gray-400 mt-1 fw-semibold fs-6">@(service.Product.Name)</span>
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div class="card-body fs-6">
|
|
||||||
<div class="d-flex flex-stack">
|
|
||||||
<div class="text-gray-700 fw-semibold me-2">Price</div>
|
|
||||||
<div class="d-flex align-items-senter">
|
|
||||||
<span class="fw-bold">@(ConfigService.Get().Store.Currency) @(service.Product.Price)</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex flex-stack">
|
|
||||||
<div class="text-gray-700 fw-semibold me-2">Renew at</div>
|
|
||||||
<div class="d-flex align-items-senter">
|
|
||||||
<span class="fw-bold">@(Formatter.FormatDate(service.RenewAt))</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="d-flex flex-stack">
|
|
||||||
<div class="text-gray-700 fw-semibold me-2">Created at</div>
|
|
||||||
<div class="d-flex align-items-senter">
|
|
||||||
<span class="fw-bold">@(Formatter.FormatDate(service.CreatedAt))</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-footer p-3">
|
|
||||||
<div class="btn-group w-100 mb-3">
|
|
||||||
<button class="btn btn-primary w-50 me-3">Manage</button>
|
|
||||||
<button class="btn btn-secondary w-50">Manage shares</button>
|
|
||||||
</div>
|
|
||||||
<div class="btn-group w-100">
|
|
||||||
<button class="btn btn-warning w-50 me-3">Renew</button>
|
|
||||||
<button class="btn btn-danger w-50">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +53,8 @@
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
|
private LazyLoader LazyLoader;
|
||||||
|
|
||||||
private Service[] MyServices;
|
private Service[] MyServices;
|
||||||
private Service[] SharedServices;
|
private Service[] SharedServices;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue