Files
SmartDBAppGit/SmartDB/Components/Account/Pages/Login.razor

354 lines
10 KiB
Plaintext

@page "/Account/Login"
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Identity
@using SmartDB.Data
@using Syncfusion.Blazor.Inputs
@using Syncfusion.Blazor.Buttons
@inject SignInManager<ApplicationUser> SignInManager
@inject ILogger<Login> Logger
@inject NavigationManager NavigationManager
@inject IdentityRedirectManager RedirectManager
<PageTitle>Accedi - SmartDB</PageTitle>
<div class="login-container">
<style>
.login-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.login-wrapper {
width: 100%;
max-width: 420px;
padding: 2rem;
}
.login-card {
background: white;
border-radius: 12px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
padding: 3rem 2.5rem;
}
.login-header {
text-align: center;
margin-bottom: 2rem;
}
.login-logo {
font-size: 2.5rem;
margin-bottom: 1rem;
color: #667eea;
font-weight: 700;
}
.login-title {
font-size: 1.75rem;
color: #333;
margin-bottom: 0.5rem;
font-weight: 600;
}
.login-subtitle {
font-size: 0.95rem;
color: #888;
margin-bottom: 2rem;
}
.form-group-custom {
margin-bottom: 1.5rem;
}
.form-group-custom label {
display: block;
margin-bottom: 0.5rem;
color: #333;
font-weight: 500;
font-size: 0.9rem;
}
::deep .e-input-group {
width: 100%;
}
::deep .e-input-group input.e-field {
border: 2px solid #e0e0e0 !important;
border-radius: 8px !important;
padding: 0.75rem 1rem !important;
font-size: 0.95rem !important;
transition: all 0.3s ease !important;
}
::deep .e-input-group input.e-field:focus {
border-color: #667eea !important;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
}
::deep .e-checkbox-wrapper {
margin-top: 0.5rem;
}
::deep .e-checkbox-wrapper label {
color: #666 !important;
font-size: 0.9rem !important;
}
.login-button {
width: 100%;
margin-top: 2rem;
margin-bottom: 1.5rem;
}
::deep .e-btn {
border-radius: 8px !important;
font-weight: 600 !important;
text-transform: uppercase !important;
letter-spacing: 0.5px !important;
transition: all 0.3s ease !important;
border: none !important;
width: 100% !important;
}
::deep .e-btn.e-primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
padding: 0.75rem 1.5rem !important;
font-size: 0.95rem !important;
min-height: 48px !important;
color: white !important;
}
::deep .e-btn.e-primary:hover:not(:disabled) {
box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4) !important;
transform: translateY(-2px) !important;
}
::deep .e-btn.e-primary:disabled {
opacity: 0.7 !important;
cursor: not-allowed !important;
}
.login-links {
text-align: center;
margin-top: 1.5rem;
}
.login-links a {
color: #667eea;
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
transition: color 0.3s ease;
}
.login-links a:hover {
color: #764ba2;
text-decoration: underline;
}
.alert-custom {
border-radius: 8px;
margin-bottom: 1.5rem;
border: none;
padding: 1rem;
}
.alert-danger-custom {
background-color: #fee;
color: #c33;
border-left: 4px solid #c33;
}
.validation-error {
color: #d32f2f;
font-size: 0.8rem;
margin-top: 0.3rem;
}
.spinner-custom {
display: inline-block;
width: 16px;
height: 16px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: white;
animation: spin 1s ease-in-out infinite;
margin-right: 0.5rem;
}
@@keyframes spin {
to { transform: rotate(360deg); }
}
.login-divider {
display: flex;
align-items: center;
margin: 2rem 0;
color: #ccc;
}
.login-divider::before,
.login-divider::after {
content: '';
flex: 1;
height: 1px;
background-color: #ccc;
}
.login-divider span {
padding: 0 1rem;
font-size: 0.85rem;
color: #999;
}
</style>
<div class="login-wrapper">
<div class="login-card">
<div class="login-header">
<div class="login-logo">🔐</div>
<h1 class="login-title">SmartDB</h1>
<p class="login-subtitle">Accedi al tuo account</p>
</div>
@if (!string.IsNullOrEmpty(errorMessage))
{
<div class="alert alert-custom alert-danger-custom">
<strong>Errore!</strong> @errorMessage
</div>
}
<EditForm Model="Input" FormName="login" OnValidSubmit="LoginUser">
<DataAnnotationsValidator />
<div class="form-group-custom">
<label for="email">Email</label>
<SfTextBox @bind-Value="Input.Email"
id="email"
Placeholder="name@example.com"
CssClass="form-control-sf"
ShowClearButton="true">
</SfTextBox>
<ValidationMessage For="() => Input.Email" class="validation-error" />
</div>
<div class="form-group-custom">
<label for="password">Password</label>
<SfTextBox @bind-Value="Input.Password"
id="password"
Placeholder="Inserisci la tua password"
CssClass="form-control-sf"
TextMode="InputType.Password"
ShowClearButton="true">
</SfTextBox>
<ValidationMessage For="() => Input.Password" class="validation-error" />
</div>
<div class="form-group-custom">
<SfCheckBox @bind-Checked="Input.RememberMe"
Label="Ricordami"
CssClass="remember-me-checkbox">
</SfCheckBox>
</div>
<div class="login-button">
<SfButton IconCss="e-icon-search"
IsPrimary="true"
Disabled="@isSubmitting"
OnClick="async () => await LoginUser()">
@if (isSubmitting)
{
<span class="spinner-custom"></span>
<span>Accesso in corso...</span>
}
else
{
<span>Accedi</span>
}
</SfButton>
</div>
<div class="login-divider">
<span>Supporto</span>
</div>
<div class="login-links">
<p>
<a href="Account/ForgotPassword">Password dimenticata?</a>
</p>
</div>
</EditForm>
</div>
</div>
</div>
@code {
private string? errorMessage;
private bool isSubmitting = false;
[CascadingParameter]
private HttpContext HttpContext { get; set; } = default!;
private InputModel Input { get; set; } = new();
protected override async Task OnInitializedAsync()
{
if (HttpMethods.IsGet(HttpContext.Request.Method))
{
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
}
}
public async Task LoginUser()
{
isSubmitting = true;
errorMessage = null;
try
{
var result = await SignInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
RedirectManager.RedirectTo("/");
}
else if (result.IsLockedOut)
{
RedirectManager.RedirectTo("Account/Lockout");
}
else
{
errorMessage = "Email o password non validi. Riprova.";
}
}
catch (Exception ex)
{
Logger.LogError(ex, "Errore durante il login");
errorMessage = "Errore durante l'accesso. Riprova più tardi.";
}
finally
{
isSubmitting = false;
}
}
private class InputModel
{
[Required(ErrorMessage = "L'email è obbligatoria")]
[EmailAddress(ErrorMessage = "Inserisci un'email valida")]
public string Email { get; set; } = "";
[Required(ErrorMessage = "La password è obbligatoria")]
[DataType(DataType.Password)]
public string Password { get; set; } = "";
[Display(Name = "Ricordami?")]
public bool RememberMe { get; set; }
}
}