Added app loaders and screen for the ui. Added identity service. Started auth screens
This commit is contained in:
27
Moonlight.Client/Implementations/AuthenticationUiHandler.cs
Normal file
27
Moonlight.Client/Implementations/AuthenticationUiHandler.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using MoonCore.Blazor.Helpers;
|
||||||
|
using Moonlight.Client.Interfaces;
|
||||||
|
using Moonlight.Client.Services;
|
||||||
|
using Moonlight.Client.UI.Screens;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Implementations;
|
||||||
|
|
||||||
|
public class AuthenticationUiHandler : IAppLoader, IAppScreen
|
||||||
|
{
|
||||||
|
public int Priority => 0;
|
||||||
|
|
||||||
|
public Task<bool> ShouldRender(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var identityService = serviceProvider.GetRequiredService<IdentityService>();
|
||||||
|
|
||||||
|
return Task.FromResult(identityService.IsLoggedIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RenderFragment Render() => ComponentHelper.FromType<AuthenticationScreen>();
|
||||||
|
|
||||||
|
public async Task Load(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
var identityService = serviceProvider.GetRequiredService<IdentityService>();
|
||||||
|
await identityService.Check();
|
||||||
|
}
|
||||||
|
}
|
||||||
7
Moonlight.Client/Interfaces/IAppLoader.cs
Normal file
7
Moonlight.Client/Interfaces/IAppLoader.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Moonlight.Client.Interfaces;
|
||||||
|
|
||||||
|
public interface IAppLoader
|
||||||
|
{
|
||||||
|
public int Priority { get; }
|
||||||
|
public Task Load(IServiceProvider serviceProvider);
|
||||||
|
}
|
||||||
10
Moonlight.Client/Interfaces/IAppScreen.cs
Normal file
10
Moonlight.Client/Interfaces/IAppScreen.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Interfaces;
|
||||||
|
|
||||||
|
public interface IAppScreen
|
||||||
|
{
|
||||||
|
public int Priority { get; }
|
||||||
|
public Task<bool> ShouldRender(IServiceProvider serviceProvider);
|
||||||
|
public RenderFragment Render();
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Helpers\" />
|
<Folder Include="Helpers\" />
|
||||||
<Folder Include="Services\" />
|
|
||||||
<Folder Include="UI\Components\" />
|
<Folder Include="UI\Components\" />
|
||||||
<Folder Include="wwwroot\css\" />
|
<Folder Include="wwwroot\css\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ var implementationService = new ImplementationService();
|
|||||||
|
|
||||||
implementationService.Register<ISidebarItemProvider, DefaultSidebarItemProvider>();
|
implementationService.Register<ISidebarItemProvider, DefaultSidebarItemProvider>();
|
||||||
|
|
||||||
|
var authUiHandler = new AuthenticationUiHandler();
|
||||||
|
implementationService.Register<IAppScreen>(authUiHandler);
|
||||||
|
implementationService.Register<IAppLoader>(authUiHandler);
|
||||||
|
|
||||||
builder.Services.AddSingleton(implementationService);
|
builder.Services.AddSingleton(implementationService);
|
||||||
|
|
||||||
await builder.Build().RunAsync();
|
await builder.Build().RunAsync();
|
||||||
57
Moonlight.Client/Services/IdentityService.cs
Normal file
57
Moonlight.Client/Services/IdentityService.cs
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
using MoonCore.Blazor.Tailwind.Services;
|
||||||
|
using MoonCore.Exceptions;
|
||||||
|
using MoonCore.Helpers;
|
||||||
|
using Moonlight.Shared.Http.Responses.Auth;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Services;
|
||||||
|
|
||||||
|
public class IdentityService
|
||||||
|
{
|
||||||
|
public string Username { get; private set; }
|
||||||
|
public string Email { get; private set; }
|
||||||
|
public string[] Permissions { get; private set; }
|
||||||
|
public bool IsLoggedIn { get; private set; }
|
||||||
|
|
||||||
|
public event Func<Task> OnStateChanged;
|
||||||
|
|
||||||
|
private readonly CookieService CookieService;
|
||||||
|
private readonly HttpApiClient ApiClient;
|
||||||
|
|
||||||
|
public IdentityService(CookieService cookieService, HttpApiClient apiClient)
|
||||||
|
{
|
||||||
|
CookieService = cookieService;
|
||||||
|
ApiClient = apiClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Check()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await ApiClient.GetJson<CheckResponse>("api/auth/check");
|
||||||
|
|
||||||
|
Username = response.Username;
|
||||||
|
Email = response.Email;
|
||||||
|
Permissions = response.Permissions;
|
||||||
|
|
||||||
|
IsLoggedIn = true;
|
||||||
|
}
|
||||||
|
catch (HttpApiException)
|
||||||
|
{
|
||||||
|
IsLoggedIn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await OnStateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Login(string token)
|
||||||
|
{
|
||||||
|
await CookieService.SetValue("token", token, 30);
|
||||||
|
await Check();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Logout()
|
||||||
|
{
|
||||||
|
await CookieService.SetValue("token", "", 30);
|
||||||
|
await Check();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +1,52 @@
|
|||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
|
@using MoonCore.PluginFramework.Services
|
||||||
|
@using Moonlight.Client.Interfaces
|
||||||
@using Moonlight.Client.UI.Partials
|
@using Moonlight.Client.UI.Partials
|
||||||
|
|
||||||
@inherits LayoutComponentBase
|
@inherits LayoutComponentBase
|
||||||
|
|
||||||
<div>
|
@inject ImplementationService ImplementationService
|
||||||
<AppSidebar Layout="this" />
|
@inject IServiceProvider ServiceProvider
|
||||||
|
@inject ILogger<MainLayout> Logger
|
||||||
|
|
||||||
<div class="lg:pl-72">
|
@if (IsLoading)
|
||||||
<AppHeader Layout="this"/>
|
{
|
||||||
|
<LazyLoader Load="Load">
|
||||||
|
|
||||||
<ErrorHandler>
|
</LazyLoader>
|
||||||
<main class="py-10">
|
}
|
||||||
<div class="px-4 sm:px-6 lg:px-8">
|
else if (CurrentScreen != null)
|
||||||
@Body
|
{
|
||||||
</div>
|
@CurrentScreen
|
||||||
</main>
|
}
|
||||||
</ErrorHandler>
|
else
|
||||||
|
{
|
||||||
|
<div>
|
||||||
|
<AppSidebar Layout="this"/>
|
||||||
|
|
||||||
<ToastLauncher />
|
<div class="lg:pl-72">
|
||||||
<ModalLauncher />
|
<AppHeader Layout="this"/>
|
||||||
|
|
||||||
|
<ErrorHandler>
|
||||||
|
<main class="py-10">
|
||||||
|
<div class="px-4 sm:px-6 lg:px-8">
|
||||||
|
<CascadingValue Value="this" IsFixed="true">
|
||||||
|
@Body
|
||||||
|
</CascadingValue>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</ErrorHandler>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
|
|
||||||
|
<ToastLauncher/>
|
||||||
|
<ModalLauncher/>
|
||||||
|
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
|
// Mobile navigation
|
||||||
public event Func<Task> OnStateChanged;
|
public event Func<Task> OnStateChanged;
|
||||||
public bool ShowMobileNavigation { get; private set; } = false;
|
public bool ShowMobileNavigation { get; private set; } = false;
|
||||||
|
|
||||||
@@ -32,4 +55,64 @@
|
|||||||
ShowMobileNavigation = !ShowMobileNavigation;
|
ShowMobileNavigation = !ShowMobileNavigation;
|
||||||
await OnStateChanged();
|
await OnStateChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// App loaders & screens
|
||||||
|
private bool IsLoading = true;
|
||||||
|
private RenderFragment? CurrentScreen;
|
||||||
|
|
||||||
|
private async Task Load(LazyLoader lazyLoader)
|
||||||
|
{
|
||||||
|
await lazyLoader.UpdateText("Retrieving data");
|
||||||
|
await RunLoaders();
|
||||||
|
|
||||||
|
await RenderScreens();
|
||||||
|
|
||||||
|
IsLoading = false;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Reload()
|
||||||
|
{
|
||||||
|
IsLoading = true;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RunLoaders()
|
||||||
|
{
|
||||||
|
var appLoaders = ImplementationService
|
||||||
|
.Get<IAppLoader>()
|
||||||
|
.OrderBy(x => x.Priority);
|
||||||
|
|
||||||
|
foreach (var loader in appLoaders) //TODO: Measure performance of every loader?
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await loader.Load(ServiceProvider);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogCritical("An app loader threw an unhandled exception: {e}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RenderScreens()
|
||||||
|
{
|
||||||
|
CurrentScreen = null;
|
||||||
|
|
||||||
|
var appScreens = ImplementationService
|
||||||
|
.Get<IAppScreen>()
|
||||||
|
.OrderBy(x => x.Priority);
|
||||||
|
|
||||||
|
foreach (var screen in appScreens)
|
||||||
|
{
|
||||||
|
if (!await screen.ShouldRender(ServiceProvider))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CurrentScreen = screen.Render();
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
18
Moonlight.Client/UI/Screens/AuthenticationScreen.razor
Normal file
18
Moonlight.Client/UI/Screens/AuthenticationScreen.razor
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
@page "/auth/register"
|
||||||
|
@page "/auth/login"
|
||||||
|
|
||||||
|
@inject NavigationManager Navigation
|
||||||
|
|
||||||
|
@{
|
||||||
|
var url = new Uri(Navigation.Uri);
|
||||||
|
var isRegister = url.LocalPath.StartsWith("/auth/register");
|
||||||
|
}
|
||||||
|
|
||||||
|
@if (isRegister)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user