Update Roles in UI and API
All checks were successful
CI/CD Pipeline / Build and Deploy with Docker Compose (push) Successful in 5m9s

This commit is contained in:
Leandro Hernan Rojas 2025-04-30 00:16:59 -03:00
parent bedee403b6
commit 508ab9de18
7 changed files with 286 additions and 169 deletions

View File

@ -142,7 +142,13 @@ namespace phronCare.API.Controllers
user.NormalizedEmail = model.Email.ToUpper(); user.NormalizedEmail = model.Email.ToUpper();
user.TwoFactorEnabled = model.TwoFactorEnabled; user.TwoFactorEnabled = model.TwoFactorEnabled;
user.LockoutEnabled = model.LockoutEnabled; user.LockoutEnabled = model.LockoutEnabled;
// Campos personalizados
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.PhoneNumber = model.PhoneNumber;
user.CompanyName = model.CompanyName;
user.Department = model.Department;
user.BirthDate = model.BirthDate;
var result = await _userManager.UpdateAsync(user); var result = await _userManager.UpdateAsync(user);
if (result.Succeeded) if (result.Succeeded)

View File

@ -7,6 +7,14 @@
public string Email { get; set; } = string.Empty; public string Email { get; set; } = string.Empty;
public bool TwoFactorEnabled { get; set; } public bool TwoFactorEnabled { get; set; }
public bool LockoutEnabled { get; set; } public bool LockoutEnabled { get; set; }
// Nuevos campos
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? PhoneNumber { get; set; }
public string? CompanyName { get; set; }
public string? Department { get; set; }
public DateTime? BirthDate { get; set; }
} }
public class User public class User
{ {
@ -24,5 +32,12 @@
public DateTimeOffset? LockoutEnd { get; set; } public DateTimeOffset? LockoutEnd { get; set; }
public bool LockoutEnabled { get; set; } public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; } public int AccessFailedCount { get; set; }
// Nuevos campos
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? Company { get; set; }
public string? Department { get; set; }
public DateTime? BirthDate { get; set; }
} }
} }

View File

@ -1,71 +1,104 @@
@page "/registration" @page "/registration"
@using System.Text.Json; @using System.Text.Json
@using System.Collections.Generic @using System.ComponentModel.DataAnnotations
@using System.ComponentModel.DataAnnotations;
@inject HttpClient httpClient @inject HttpClient httpClient
@inject IToastService toastService @inject IToastService toastService
@inject NavigationManager navigation @inject NavigationManager navigation
<h1>Registro de Usuario</h1> <div class="card mt-4" style="zoom:90%">
<div class="card-header text-center">
<EditForm Model="user" OnValidSubmit="RegistrarUsuario"> <h3 class="card-title">Registro de Usuario</h3>
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-group">
<label for="InputUserName">Nombre de Usuario:</label>
<div class="col-md-4">
<InputText id="InputUserName" @bind-Value="user.UserName" class="form-control" />
</div>
</div> </div>
<div class="form-group"> <div class="card-body">
<label for="InputEmail">Correo Electrónico:</label> <EditForm Model="user" OnValidSubmit="RegistrarUsuario">
<div class="col-md-4"> <DataAnnotationsValidator />
<InputText id="InputEmail" @bind-Value="user.EmailAddress" class="form-control" /> <ValidationSummary />
</div>
<div class="row">
<div class="col-md-6">
<label for="InputUserName">Nombre de Usuario:</label>
<InputText id="InputUserName" @bind-Value="user.UserName" class="form-control" />
</div>
<div class="col-md-6">
<label for="InputEmail">Correo Electrónico:</label>
<InputText id="InputEmail" @bind-Value="user.EmailAddress" class="form-control" />
</div>
</div>
<div class="row mt-3">
<div class="col-md-6">
<label for="InputPassword">Contraseña:</label>
<InputText id="InputPassword" @bind-Value="user.Password" type="password" class="form-control" />
</div>
<div class="col-md-6">
<label for="InputConfirmPassword">Confirmar Contraseña:</label>
<InputText id="InputConfirmPassword" @bind-Value="confirmPassword" type="password" class="form-control" />
</div>
</div>
<div class="row mt-3">
<div class="col-md-6">
<label for="InputRole">Rol:</label>
<InputSelect @bind-Value="user.Role" class="form-control">
@foreach (var role in roles)
{
<option value="@role.Name">@role.Name</option>
}
</InputSelect>
</div>
<div class="col-md-6">
<label for="PhoneNumber">Teléfono:</label>
<InputText id="PhoneNumber" @bind-Value="user.PhoneNumber" class="form-control" />
</div>
</div>
<div class="row mt-3">
<div class="col-md-6">
<label for="FirstName">Nombre:</label>
<InputText id="FirstName" @bind-Value="user.FirstName" class="form-control" />
</div>
<div class="col-md-6">
<label for="LastName">Apellido:</label>
<InputText id="LastName" @bind-Value="user.LastName" class="form-control" />
</div>
</div>
<div class="row mt-3">
<div class="col-md-6">
<label for="Company">Empresa:</label>
<InputText id="Company" @bind-Value="user.Company" class="form-control" />
</div>
<div class="col-md-6">
<label for="Department">Departamento:</label>
<InputText id="Department" @bind-Value="user.Department" class="form-control" />
</div>
</div>
<div class="row mt-3">
<div class="col-md-6">
<label for="BirthDate">Fecha de nacimiento:</label>
<InputDate id="BirthDate" @bind-Value="user.BirthDate" class="form-control" />
</div>
</div>
</EditForm>
</div> </div>
<div class="form-group"> <div class="card-footer d-flex justify-content-end">
<label for="InputPassword">Contraseña:</label> <button type="submit" class="btn btn-primary me-2" @onclick="RegistrarUsuario">Registrar</button>
<div class="col-md-4"> <button type="button" class="btn btn-secondary" @onclick="Cancel">Cancelar</button>
<InputText id="InputPassword" @bind-Value="user.Password" type="password" class="form-control" />
</div>
</div> </div>
</div>
<div class="form-group">
<label for="InputConfirmPassword">Confirmar Contraseña:</label>
<div class="col-md-4">
<InputText id="InputConfirmPassword" @bind-Value="confirmPassword" type="password" class="form-control" />
</div>
</div>
<div class="form-group">
<label for="InputRole">Rol:</label>
<div class="col-md-4">
<InputSelect @bind-Value="user.Role" class="form-control">
@foreach (var role in roles)
{
<option value="@role.Name">@role.Name</option>
}
</InputSelect>
</div>
</div>
<br />
<button type="submit" class="btn btn-primary">Registrar</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancelar</button>
</EditForm>
@code { @code {
private User user = new User(); private User user = new();
private string confirmPassword=string.Empty; private string confirmPassword = string.Empty;
public List<Role> roles = new();
public List<Role> roles = new List<Role>(); // Reemplaza con tu lista de roles reales
private const int USERNAME_VALID_LENGTH = 8; private const int USERNAME_VALID_LENGTH = 8;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
roles = await GetAllRoles(); roles = await GetAllRoles();
@ -81,22 +114,23 @@
{ {
if (user.UserName.Length < USERNAME_VALID_LENGTH) if (user.UserName.Length < USERNAME_VALID_LENGTH)
{ {
toastService.ShowError($"longitud de nombre minima: {USERNAME_VALID_LENGTH} caracteres. ¡Inténtalo de nuevo!"); toastService.ShowError($"El nombre de usuario debe tener al menos {USERNAME_VALID_LENGTH} caracteres.");
} }
else if (user.Password != confirmPassword) else if (user.Password != confirmPassword)
{ {
toastService.ShowError("Las contraseñas no coinciden. ¡Inténtalo de nuevo!"); toastService.ShowError("Las contraseñas no coinciden.");
} }
else if (string.IsNullOrEmpty(user.Role)) else if (string.IsNullOrEmpty(user.Role))
{ {
toastService.ShowWarning("Debes seleccionar un rol."); toastService.ShowWarning("Debe seleccionar un rol.");
} }
else else
{ {
await CreateUser(); await CreateUser();
} }
} }
public async Task CreateUser()
private async Task CreateUser()
{ {
var requestContent = new StringContent(JsonSerializer.Serialize(user), System.Text.Encoding.UTF8, "application/json"); var requestContent = new StringContent(JsonSerializer.Serialize(user), System.Text.Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync("/api/Authentication/register/", requestContent); var response = await httpClient.PostAsync("/api/Authentication/register/", requestContent);
@ -111,18 +145,26 @@
toastService.ShowError(errorResponse); toastService.ShowError(errorResponse);
} }
} }
public void Cancel()
private void Cancel()
{ {
navigation.NavigateTo("/users"); navigation.NavigateTo("/users");
} }
public class User public class User
{ {
[Required(ErrorMessage = "El Username es un dato obligatorio")] public string UserName { get; set; } = string.Empty; [Required] public string UserName { get; set; } = string.Empty;
[EmailAddress, Required(ErrorMessage = "El correo electronico es un dato obligatorio")] public string EmailAddress { get; set; } = string.Empty; [EmailAddress, Required] public string EmailAddress { get; set; } = string.Empty;
[Required(ErrorMessage = "La contraseña es un dato obligatorio")] public string Password { get; set; } = string.Empty; [Required] public string Password { get; set; } = string.Empty;
[Required(ErrorMessage = "El rol es un dato obligatorio")] public string Role { get; set; } = string.Empty; [Required] public string Role { get; set; } = string.Empty;
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? PhoneNumber { get; set; }
public string? Company { get; set; }
public string? Department { get; set; }
public DateTime? BirthDate { get; set; }
} }
public class Role public class Role
{ {
public string Id { get; set; } = string.Empty; public string Id { get; set; } = string.Empty;

View File

@ -1,5 +1,5 @@
@page "/roleform/edit/{id}" @page "/role/{id}"
@page "/roleform/create" @page "/role/create"
@using System.Net.Http.Headers; @using System.Net.Http.Headers;
@using System.Text.Json; @using System.Text.Json;
@ -9,8 +9,14 @@
@inject IToastService toastService @inject IToastService toastService
@inject AuthenticationStateProvider authenticationStateProvider @inject AuthenticationStateProvider authenticationStateProvider
<h1>Editar Rol</h1> @if (role.Id is null)
{
<h1>Crear Nuevo Rol</h1>
}
else
{
<h1>Editar Rol</h1>
}
@if (role is not null) @if (role is not null)
{ {
<EditForm Model="role" OnValidSubmit="UpsertRole"> <EditForm Model="role" OnValidSubmit="UpsertRole">
@ -42,10 +48,8 @@
[Parameter] [Parameter]
public string id { get; set; } = string.Empty; public string id { get; set; } = string.Empty;
private Role? role; private Role? role;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
if ( id is not null) if ( id is not null)
{ {
role = await GetRole(id); role = await GetRole(id);
@ -55,6 +59,7 @@
role = new Role(); role = new Role();
} }
} }
public async Task<Role?> GetRole(string roleId) public async Task<Role?> GetRole(string roleId)
{ {
var customAuthStateProvider = (CustomAuthorizationProvider)authenticationStateProvider; var customAuthStateProvider = (CustomAuthorizationProvider)authenticationStateProvider;
@ -75,7 +80,6 @@
}; };
Role role = JsonSerializer.Deserialize<Role>(jsonResponse, options) ?? new Role(); Role role = JsonSerializer.Deserialize<Role>(jsonResponse, options) ?? new Role();
return role; return role;
} }
} }
catch catch
@ -88,7 +92,7 @@
} }
private async Task UpsertRole() private async Task UpsertRole()
{ {
if(role is null) if(role.Id is null)
{ {
await CreateRole(); await CreateRole();
} }
@ -99,23 +103,8 @@
} }
public async Task UpdateRole() public async Task UpdateRole()
{ {
// var requestContent = new StringContent(JsonSerializer.Serialize(role), System.Text.Encoding.UTF8, "application/json");
// var response = await _httpClient.PutAsync("/api/Account/UpdateRole/"+role.Id, requestContent);
// if (response.IsSuccessStatusCode)
// {
// toastService.ShowSuccess("El registro fue actualizado correctamente!");
// Navigation.NavigateTo("/roles"); // Redirige a la página de roles después de la actualización
// }
// else
// {
// // Manejar errores de actualización
// var errorResponse = await response.Content.ReadAsStringAsync();
// toastService.ShowError(errorResponse);
// }
if (role == null) if (role == null)
{ {
// Maneja el caso en que role es null
toastService.ShowError("Role no está definido."); toastService.ShowError("Role no está definido.");
return; return;
} }
@ -135,10 +124,10 @@
toastService.ShowError(errorResponse); toastService.ShowError(errorResponse);
} }
} }
public async Task CreateRole() public async Task CreateRole()
{ {
var newConcurrencyStamp = Guid.NewGuid().ToString(); var newConcurrencyStamp = Guid.NewGuid().ToString();
var requestContent = new StringContent(JsonSerializer.Serialize(role), System.Text.Encoding.UTF8, "application/json"); var requestContent = new StringContent(JsonSerializer.Serialize(role), System.Text.Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync("/api/Account/CreateRole/", requestContent); var response = await _httpClient.PostAsync("/api/Account/CreateRole/", requestContent);
var errorResponse = await response.Content.ReadAsStringAsync(); var errorResponse = await response.Content.ReadAsStringAsync();

View File

@ -10,7 +10,7 @@
@inject AuthenticationStateProvider authenticationStateProvider @inject AuthenticationStateProvider authenticationStateProvider
<h1>Lista de Roles</h1> <h1>Lista de Roles</h1>
<a href="/roleform/create" class="btn btn-dark">Crear Nuevo Rol</a> <a href="/role/create" class="btn btn-dark">Crear Nuevo Rol</a>
<br/> <br/>
@if (roles != null && roles.Count > 0) @if (roles != null && roles.Count > 0)
{ {
@ -100,7 +100,7 @@ else
} }
public void EditRole(string roleId) public void EditRole(string roleId)
{ {
navigation.NavigateTo($"/roleform/edit/{roleId}"); navigation.NavigateTo($"/role/{roleId}");
} }
private void ConfirmDelete(string roleId) private void ConfirmDelete(string roleId)
{ {

View File

@ -1,54 +1,80 @@
@page "/userform/edit/{Id}" @page "/userform/edit/{Id}"
@using System.Net.Http.Headers; @using System.Net.Http.Headers
@using System.Text.Json; @using System.Text.Json
@using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Forms
@inject HttpClient _httpClient @inject HttpClient _httpClient
@inject NavigationManager Navigation @inject NavigationManager Navigation
@inject IToastService toastService
@inject AuthenticationStateProvider authenticationStateProvider @inject AuthenticationStateProvider authenticationStateProvider
@inject IToastService toastService
<h1>Editar Usuario</h1> <div class="card mt-4" style="zoom: 90%">
@if (user is not null) <div class="card-header text-center">
{ <h3 class="card-title">Editar Usuario</h3>
<EditForm Model="@user" OnSubmit="UpdateUser"> </div>
<div class="form-group">
<label for="Name">Id del Rol</label> @if (user is not null)
<div class="col-md-4"> {
<InputText disabled="1" @bind-Value="user.Id" id="Id" class="form-control" /> <EditForm Model="@user" OnValidSubmit="UpdateUser">
<div class="card-body">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="row">
<div class="col-sm-12 col-md-6">
<label>Nombre:</label>
<InputText @bind-Value="user.FirstName" class="form-control" />
</div>
<div class="col-sm-12 col-md-6">
<label>Apellido:</label>
<InputText @bind-Value="user.LastName" class="form-control" />
</div>
</div>
<div class="row mt-3">
<div class="col-sm-12 col-md-6">
<label>Teléfono:</label>
<InputText @bind-Value="user.PhoneNumber" class="form-control" />
</div>
<div class="col-sm-12 col-md-6">
<label>Empresa:</label>
<InputText @bind-Value="user.CompanyName" class="form-control" />
</div>
</div>
<div class="row mt-3">
<div class="col-sm-12 col-md-6">
<label>Departamento:</label>
<InputText @bind-Value="user.Department" class="form-control" />
</div>
<div class="col-sm-12 col-md-6">
<label>Fecha de nacimiento:</label>
<InputDate @bind-Value="user.BirthDate" class="form-control" />
</div>
</div>
<div class="row mt-4">
<div class="col-sm-12 col-md-6 d-flex align-items-center">
<div class="form-check form-switch">
<InputCheckbox id="TwoFactorEnabled" @bind-Value="user.TwoFactorEnabled" class="form-check-input" />
<label class="form-check-label ms-2" for="TwoFactorEnabled">Autenticación de dos factores</label>
</div>
</div>
<div class="col-sm-12 col-md-6 d-flex align-items-center">
<div class="form-check form-switch">
<InputCheckbox id="LockoutEnabled" @bind-Value="user.LockoutEnabled" class="form-check-input" />
<label class="form-check-label ms-2" for="LockoutEnabled">Bloqueo de cuenta</label>
</div>
</div>
</div>
</div> </div>
</div>
<div class="form-group"> <div class="card-footer d-flex justify-content-end">
<label for="Username">Nombre de usuario:</label> <button type="submit" class="btn btn-primary me-2">Guardar</button>
<div class="col-md-4"> <button type="button" class="btn btn-secondary" @onclick="Cancel">Cancelar</button>
<InputText id="Username" @bind-Value="user.UserName" class="form-control" />
</div> </div>
</div> </EditForm>
<div class="form-group"> }
<label for="Username">Correo electrónico:</label> </div>
<div class="col-md-4">
<InputText id="Email" @bind-Value="user.Email" class="form-control" />
</div>
</div>
<div class="form-group">
<label for="TwoFactorEnabled">Autenticación de dos factores:</label>
<div class="col-md-4">
<InputCheckbox id="TwoFactorEnabled" @bind-Value="user.TwoFactorEnabled"/>
</div>
</div>
<div class="form-group">
<label for="LockoutEnabled">Bloqueo de cuenta:</label>
<div class="col-md-4">
<InputCheckbox id="LockoutEnabled" @bind-Value="user.LockoutEnabled"/>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Guardar</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">Cancelar</button>
</div>
</EditForm>
}
@code { @code {
[Parameter] [Parameter]
@ -57,12 +83,12 @@
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
if (id is not null) if (id is not null)
{ {
user = await GetUser(id); user = await GetUser(id);
} }
} }
public async Task<UserUpdate?> GetUser(string userId) public async Task<UserUpdate?> GetUser(string userId)
{ {
var customAuthStateProvider = (CustomAuthorizationProvider)authenticationStateProvider; var customAuthStateProvider = (CustomAuthorizationProvider)authenticationStateProvider;
@ -77,28 +103,31 @@
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
var jsonResponse = await response.Content.ReadAsStringAsync(); var jsonResponse = await response.Content.ReadAsStringAsync();
var options = new JsonSerializerOptions var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
{
PropertyNameCaseInsensitive = true
};
var deserializedUser = JsonSerializer.Deserialize<User>(jsonResponse, options); var deserializedUser = JsonSerializer.Deserialize<User>(jsonResponse, options);
User user = deserializedUser ?? new User(); User user = deserializedUser ?? new User();
// user = JsonSerializer.Deserialize<User>(jsonResponse, options); return new UserUpdate
UserUpdate require = new UserUpdate(); {
require.Id = user.Id; Id = user.Id,
require.UserName = user.UserName; UserName = user.UserName,
require.Email = user.Email; Email = user.Email,
require.LockoutEnabled = user.LockoutEnabled; LockoutEnabled = user.LockoutEnabled,
require.TwoFactorEnabled = user.TwoFactorEnabled; TwoFactorEnabled = user.TwoFactorEnabled,
return require; FirstName = user.FirstName,
LastName = user.LastName,
PhoneNumber = user.PhoneNumber,
CompanyName = user.CompanyName,
Department = user.Department,
BirthDate = user.BirthDate
};
} }
} }
catch catch
{ {
return null; return null;
} }
}; }
return null; return null;
} }
@ -125,10 +154,12 @@
toastService.ShowError(ex.Message); toastService.ShowError(ex.Message);
} }
} }
public void Cancel() public void Cancel()
{ {
Navigation.NavigateTo("/users"); Navigation.NavigateTo("/users");
} }
public class User public class User
{ {
public string Id { get; set; } = string.Empty; public string Id { get; set; } = string.Empty;
@ -145,14 +176,27 @@
public DateTimeOffset? LockoutEnd { get; set; } public DateTimeOffset? LockoutEnd { get; set; }
public bool LockoutEnabled { get; set; } public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; } public int AccessFailedCount { get; set; }
// Campos personalizados
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? CompanyName { get; set; }
public string? Department { get; set; }
public DateTime? BirthDate { get; set; }
} }
public class UserUpdate public class UserUpdate
{ {
public string Id { get; set; } = string.Empty; public string Id { get; set; } = string.Empty;
public string UserName { get; set; } = string.Empty; public string UserName { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty; public string Email { get; set; } = string.Empty;
public string? FirstName { get; set; }
public string? LastName { get; set; }
public string? PhoneNumber { get; set; }
public string? CompanyName { get; set; }
public string? Department { get; set; }
public DateTime? BirthDate { get; set; }
public bool TwoFactorEnabled { get; set; } public bool TwoFactorEnabled { get; set; }
public bool LockoutEnabled { get; set; } public bool LockoutEnabled { get; set; }
} }
} }

View File

@ -10,41 +10,53 @@
@inject AuthenticationStateProvider authenticationStateProvider @inject AuthenticationStateProvider authenticationStateProvider
<h1>Lista de Usuarios</h1> <h1>Lista de Usuarios</h1>
<a href="/registration" class="btn btn-dark">Registrar usuario</a> <a href="/registration" class="btn btn-dark mb-3">Registrar usuario</a>
<br />
@if (users != null && users.Count > 0) @if (users != null && users.Count > 0)
{ {
<table class="table"> <table class="table table-hover">
<thead> <thead class="table-secondary">
<tr> <tr>
<th>Id</th> <th class="text-center align-middle">Nombre completo</th>
<th>Username</th> <th class="text-center align-middle">Usuario</th>
<th>Email</th> <th class="text-center align-middle">Email</th>
<th>Confirmed</th> <th class="text-center align-middle">Teléfono</th>
<th>2FA</th> <th class="text-center align-middle">Empresa</th>
<th>Access Failed</th> <th class="text-center align-middle">Departamento</th>
<th>Lockout</th> <th class="text-center align-middle">Verificado</th>
<th>Actions</th> <th class="text-center align-middle">2FA</th>
<th class="text-center align-middle">#Intentos</th>
<th class="text-center align-middle">Lockout</th>
<th class="text-center align-middle">Acciones</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach (var user in users) @foreach (var user in users)
{ {
<tr> <tr>
<td>@user.Id</td> <td>@user.FullName</td>
<td>@user.UserName</td> <td>@user.UserName</td>
<td>@user.Email</td> <td>@user.Email</td>
<td>@user.EmailConfirmed</td> <td>@user.PhoneNumber</td>
<td>@user.TwoFactorEnabled</td> <td>@user.CompanyName</td>
<td>@user.AccessFailedCount</td> <td>@user.Department</td>
<td>@user.LockoutEnabled</td> <td class="text-center align-middle">@(user.EmailConfirmed ? "✅" : "❌")</td>
<td class="text-center align-middle">@(user.TwoFactorEnabled ? "✅" : "❌")</td>
<td class="text-center align-middle">@user.AccessFailedCount</td>
<td class="text-center align-middle">@(user.LockoutEnabled ? "✅" : "❌")</td>
<td> <td>
<button class="btn btn-primary btn-margin" @onclick="() => EditUser(user.Id)"> <span class="fa fa-pencil"></span> </button> <button class="btn btn-sm btn-primary me-1" @onclick="() => EditUser(user.Id)">
<i class="fa fa-pencil"></i>
</button>
@if (user.UserName.ToLower() != "superdmin") @if (user.UserName.ToLower() != "superdmin")
{ {
<button class="btn btn-danger btn-margin" @onclick="() => ConfirmDelete(user.Id)"> <span class="fa fa-trash"></span> </button> <button class="btn btn-sm btn-danger me-1" @onclick="() => ConfirmDelete(user.Id)">
<i class="fa fa-trash"></i>
</button>
} }
<button class="btn btn-warning btn-margin" @onclick="() => RecoveryPassword(user.Email)"> <span class="fa fa-user-secret"></span> </button> <button class="btn btn-sm btn-warning" @onclick="() => RecoveryPassword(user.Email)">
<i class="fa fa-user-secret"></i>
</button>
</td> </td>
</tr> </tr>
} }
@ -53,8 +65,7 @@
} }
else else
{ {
<br /> <p class="mt-3">Cargando información o no hay usuarios disponibles...</p>
<p>Cargando informacion...</p>
} }
@code { @code {
@ -69,7 +80,7 @@ else
try try
{ {
var response = await _httpClient.GetAsync("/api/Account/GetAllUsers"); var response = await _httpClient.GetAsync("/api/Account/GetAllUsers");
Console.WriteLine(token.token); //Console.WriteLine(token.token);
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
var jsonResponse = await response.Content.ReadAsStringAsync(); var jsonResponse = await response.Content.ReadAsStringAsync();
@ -206,5 +217,15 @@ else
public DateTimeOffset? LockoutEnd { get; set; } public DateTimeOffset? LockoutEnd { get; set; }
public bool LockoutEnabled { get; set; } public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; } public int AccessFailedCount { get; set; }
// Nuevos campos
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string FullName { get; set; } = string.Empty;
public string Address { get; set; } = string.Empty;
public string Department { get; set; } = string.Empty;
public string CompanyName { get; set; } = string.Empty;
public DateTime? BirthDate { get; set; }
} }
} }