feat(theme): LoginCard
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
@namespace ZB.MOM.WW.Theme
|
||||
@* Components/LoginCard.razor — static form-POST sign-in card. *@
|
||||
<div class="login-wrap rise">
|
||||
<section class="panel">
|
||||
<div class="login-body">
|
||||
<h1 class="login-title">@Product — sign in</h1>
|
||||
<form method="post" action="@Action" data-enhance="false">
|
||||
@if (!string.IsNullOrEmpty(ReturnUrl))
|
||||
{
|
||||
<input type="hidden" name="returnUrl" value="@ReturnUrl" />
|
||||
}
|
||||
@ChildContent @* e.g. <AntiforgeryToken/> supplied by the app *@
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="username">Username</label>
|
||||
<input id="username" name="username" type="text"
|
||||
class="form-control form-control-sm" autocomplete="username" />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="password">Password</label>
|
||||
<input id="password" name="password" type="password"
|
||||
class="form-control form-control-sm" autocomplete="current-password" />
|
||||
</div>
|
||||
@if (!string.IsNullOrWhiteSpace(Error))
|
||||
{
|
||||
<div class="panel notice login-error">@Error</div>
|
||||
}
|
||||
<button class="btn btn-primary w-100" type="submit">Sign in</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
[Parameter, EditorRequired] public string Product { get; set; } = string.Empty;
|
||||
[Parameter] public string Action { get; set; } = "/auth/login";
|
||||
[Parameter] public string? ReturnUrl { get; set; }
|
||||
[Parameter] public string? Error { get; set; }
|
||||
[Parameter] public RenderFragment? ChildContent { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
namespace ZB.MOM.WW.Theme.Tests;
|
||||
|
||||
public class LoginCardTests : TestContext
|
||||
{
|
||||
[Fact]
|
||||
public void Posts_to_action_with_username_password_fields()
|
||||
{
|
||||
var cut = RenderComponent<LoginCard>(p => p
|
||||
.Add(x => x.Product, "OtOpcUa")
|
||||
.Add(x => x.Action, "/auth/login"));
|
||||
var form = cut.Find("form");
|
||||
Assert.Equal("post", form.GetAttribute("method"));
|
||||
Assert.Equal("/auth/login", form.GetAttribute("action"));
|
||||
Assert.NotNull(cut.Find("input#username"));
|
||||
Assert.NotNull(cut.Find("input#password"));
|
||||
Assert.Contains("OtOpcUa", cut.Find(".login-title").TextContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReturnUrl_renders_hidden_input()
|
||||
{
|
||||
var cut = RenderComponent<LoginCard>(p => p
|
||||
.Add(x => x.Product, "OtOpcUa")
|
||||
.Add(x => x.ReturnUrl, "/clusters"));
|
||||
var hidden = cut.Find("input[name=returnUrl]");
|
||||
Assert.Equal("/clusters", hidden.GetAttribute("value"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Error_renders_notice()
|
||||
{
|
||||
var cut = RenderComponent<LoginCard>(p => p
|
||||
.Add(x => x.Product, "OtOpcUa")
|
||||
.Add(x => x.Error, "Bad credentials"));
|
||||
Assert.Contains("Bad credentials", cut.Find(".notice").TextContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void No_returnUrl_no_hidden_input()
|
||||
{
|
||||
var cut = RenderComponent<LoginCard>(p => p.Add(x => x.Product, "OtOpcUa"));
|
||||
Assert.Empty(cut.FindAll("input[name=returnUrl]"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user