[frontend/components] Add registration page and update login page style (ISH-472)

This commit is contained in:
Lilian 2024-11-23 19:31:11 +01:00
parent c84156e946
commit a130934787
No known key found for this signature in database
10 changed files with 195 additions and 22 deletions

View file

@ -6,6 +6,7 @@ using Iceshrimp.Backend.Core.Configuration;
using Iceshrimp.Backend.Core.Database;
using Iceshrimp.Backend.Core.Extensions;
using Iceshrimp.Backend.Core.Middleware;
using Iceshrimp.Backend.Core.Services;
using Iceshrimp.Shared.Schemas.Web;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
@ -17,16 +18,18 @@ namespace Iceshrimp.Backend.Controllers.Web;
[EnableRateLimiting("sliding")]
[Route("/api/iceshrimp/instance")]
[Produces(MediaTypeNames.Application.Json)]
public class InstanceController(DatabaseContext db, UserRenderer userRenderer, IOptions<Config.InstanceSection> config) : ControllerBase
public class InstanceController(DatabaseContext db, UserRenderer userRenderer, IOptions<Config.InstanceSection> instanceConfig, IOptions<Config.SecuritySection> securityConfig, MetaService meta) : ControllerBase
{
[HttpGet]
[ProducesResults(HttpStatusCode.OK)]
public InstanceResponse GetInfo()
public async Task<InstanceResponse> GetInfo()
{
return new InstanceResponse
{
AccountDomain = config.Value.AccountDomain,
WebDomain = config.Value.WebDomain,
AccountDomain = instanceConfig.Value.AccountDomain,
WebDomain = instanceConfig.Value.WebDomain,
Registration = (Registrations)securityConfig.Value.Registrations,
Name = await meta.GetAsync(MetaEntity.InstanceName)
};
}

View file

@ -1,5 +0,0 @@
@inherits LayoutComponentBase
<div class="page">
@Body
</div>

View file

@ -0,0 +1,8 @@
@inherits LayoutComponentBase
<div class="header">
<img class="logo" src="/_content/Iceshrimp.Assets.Branding/welcome-logo.svg" />
</div>
<div class="page">
@Body
</div>

View file

@ -0,0 +1,10 @@
.header {
display: flex;
width: 100%;
padding: 1rem;
}
.logo {
object-fit: contain;
height: 2rem
}

View file

@ -6,13 +6,16 @@
@using Iceshrimp.Frontend.Localization
@using Iceshrimp.Shared.Schemas.Web
@using Microsoft.Extensions.Localization
@inject ApiService Api
@inject SessionService SessionService
@inject NavigationManager Navigation
@inject ApiService Api
@inject SessionService SessionService
@inject NavigationManager Navigation
@inject IStringLocalizer<Localization> Loc;
@layout LoginLayout
@inject MetadataService Metadata;
@layout UnauthLayout
<div class="body">
<span><h3>Login</h3></span>
<img class="logo" src="/_content/Iceshrimp.Assets.Branding/splash.png"/>
<span>
<h3>@Loc["Login to {0}", Name ?? "this Iceshrimp.NET Instance."]</h3></span>
<div class="login-form">
<input placeholder="@Loc["Username"]" required="required"
@bind="@Username"/>
@ -30,8 +33,6 @@
<span>Authentication Failed</span>
}
<span><p>A login page is being constructed here.</p></span>
</div>
@code {
[SupplyParameterFromQuery(Name = "rd")]
@ -42,6 +43,7 @@
private string? Username { get; set; }
private bool Loading { get; set; }
private bool Failure { get; set; }
private string? Name { get; set; }
private async Task Submit()
{
@ -76,7 +78,7 @@
MovedTo = res.User.MovedTo
});
SessionService.SetSession(res.User.Id);
Navigation.NavigateTo(Uri.TryCreate(Redirect, UriKind.Relative, out _) ? Redirect : "/");
Navigation.NavigateTo(Uri.TryCreate(Redirect, UriKind.Relative, out _) ? Redirect : "/", true);
break;
case AuthStatusEnum.Guest:
Failure = true;
@ -94,4 +96,10 @@
StateHasChanged(); // Manually triggering a state update, else component will not re-render.
}
}
protected override async Task OnInitializedAsync()
{
var metadata = await Metadata.Instance.Value;
Name = metadata.Name;
}
}

View file

@ -5,7 +5,12 @@
}
.login-form {
margin-top: 1rem;
display: flex;
flex-direction: column;
align-items: center;
}
.logo {
height: 3rem;
}

View file

@ -0,0 +1,117 @@
@page "/register"
@using Iceshrimp.Frontend.Core.Miscellaneous
@using Iceshrimp.Frontend.Core.Schemas
@using Iceshrimp.Frontend.Core.Services
@using Iceshrimp.Shared.Schemas.Web
@using Microsoft.Extensions.Localization
@layout UnauthLayout
@inject IStringLocalizer<Register> Loc;
@inject MetadataService Metadata;
@inject ApiService Api;
@inject SessionService SessionService;
@inject NavigationManager Navigation;
@if (State is State.Loaded)
{
<div class="body">
<img class="logo" src="/_content/Iceshrimp.Assets.Branding/splash.png"/>
<span>
<h3>@Loc["Register on {0}", Name ?? "this Iceshrimp.NET Instance."]</h3></span>
@if (RegistrationAvailability is not Registrations.Closed)
{
<div class="register-form">
<input placeholder="@Loc["Username"]" required="required"
@bind="@Username"/>
<input type="password" required="required" placeholder="@Loc["Password"]"
@bind="@Password"/>
@if (RegistrationAvailability is Registrations.Invite)
{
<input required="required" placeholder="@Loc["Invite"]" @bind="@Invite"/>
}
<button class="button" @onclick="Submit" disabled="@Loading">@Loc["Register"]</button>
</div>
@if (Result is RegistrationResult.Failure)
{
<div>@Loc[RegistrationError ?? string.Empty]</div>
}
}
@if (RegistrationAvailability is Registrations.Closed)
{
<div>@Loc["Registrations for this instance are closed."]</div>
}
</div>
}
@code {
private string? Username { get; set; }
private string? Password { get; set; }
private string? Invite { get; set; }
private bool Loading { get; set; }
private RegistrationResult Result { get; set; }
private Registrations RegistrationAvailability { get; set; }
private State State { get; set; } = State.Loading;
private string? RegistrationError { get; set; }
private string? Name { get; set; }
private async Task Submit()
{
Loading = true;
StateHasChanged();
if (Username is null || Password is null)
{
Result = RegistrationResult.Failure;
RegistrationError = "Please fill out all fields";
Loading = false;
return;
}
var registration = new RegistrationRequest { Username = Username, Password = Password, Invite = Invite, };
try
{
var res = await Api.Auth.RegisterAsync(registration);
if (res.Status is AuthStatusEnum.Authenticated)
{
SessionService.AddUser(new StoredUser
{ // Token nor user will ever be null on an authenticated response
Id = res.User!.Id,
Username = res.User.Username,
DisplayName = res.User.DisplayName,
AvatarUrl = res.User.AvatarUrl,
BannerUrl = res.User.BannerUrl,
InstanceName = res.User.InstanceName,
InstanceIconUrl = res.User.InstanceIconUrl,
Token = res.Token!,
Host = res.User.Host,
IsAdmin = res.IsAdmin ?? false,
Emojis = res.User.Emojis,
MovedTo = res.User.MovedTo
});
SessionService.SetSession(res.User.Id);
Navigation.NavigateTo("/");
}
Loading = false;
}
catch (ApiException e)
{
RegistrationError = e.Response.Message;
Result = RegistrationResult.Failure;
Loading = false;
StateHasChanged();
}
}
private enum RegistrationResult
{
Incomplete,
Success,
Failure
}
protected override async Task OnInitializedAsync()
{
var metadata = await Metadata.Instance.Value;
RegistrationAvailability = metadata.Registration;
State = State.Loaded;
Name = metadata.Name;
}
}

View file

@ -0,0 +1,20 @@
.body {
display: flex;
flex-direction: column;
align-items: center;
}
.register-form {
margin-top: 1rem;
display: flex;
flex-direction: column;
align-items: center;
}
input:invalid {
border: 0.1rem solid var(--highlight-color);
}
.logo {
height: 3rem;
}

View file

@ -2,10 +2,10 @@ namespace Iceshrimp.Shared.Schemas.Web;
public class InstanceResponse
{
public required string AccountDomain { get; set; }
public required string WebDomain { get; set; }
// TODO: Add more instance metadata
public required string AccountDomain { get; set; }
public required string WebDomain { get; set; }
public required Registrations Registration { get; set; }
public required string? Name { get; set; }
}
public class StaffResponse
@ -13,3 +13,10 @@ public class StaffResponse
public required List<UserResponse> Admins { get; set; }
public required List<UserResponse> Moderators { get; set; }
}
public enum Registrations
{
Closed = 0,
Invite = 1,
Open = 2
}