Files
ERP_Distribution/Distribution/Features/User/UserService.cs
Kalana B. Thilakarathna 531b3a7fef Redesign login UI, add theme toggle, refactor user update
- Redesigned login page with two-panel layout and branding
- Added HexaDistro logo and theme toggle to sidebar/header
- Refactored user update: roles via update endpoint, removed assignRole API/controller
- Extended UpdateUserRequest for username, role, password changes
- UserService.UpdateAsync syncs changes with AuthHex, with rollback
- Stock balances client dedupes by itemId-locationId
- Middleware matcher excludes static assets from auth checks
- Improved localStorage clearing for user context
- Added lucide-react for icons
- Minor UI/code cleanups for consistency and UX
2026-10-19 02:20:14 +05:30

174 lines
5.8 KiB
C#

using Distribution.Features.Auth;
using Distribution.Infra.UoW;
namespace Distribution.Features.User;
public class UserService(IUserRepository repo, IUnitOfWork uow, IAuthHexClient authHex)
{
private static UserResponse ToResponse(Models.User u) =>
new(u.Id, u.Username, u.FullName, u.FK_RoleId, u.Role?.Name ?? string.Empty,
u.FK_ReportsToUserId, u.IsActive, u.CreatedAt, u.UpdatedAt);
public async Task<List<UserResponse>> GetAllAsync() =>
(await repo.GetAllAsync())
.Where(u => u.IsActive)
.Select(ToResponse)
.ToList();
public async Task<UserResponse?> GetByIdAsync(Guid id)
{
var user = await repo.GetByIdAsync(id);
if (user is null || !user.IsActive) return null;
return ToResponse(user);
}
public async Task<UserResponse> CreateAsync(CreateUserRequest request, CancellationToken ct = default)
{
var user = new Models.User
{
Username = request.Username,
FullName = request.FullName,
FK_RoleId = request.RoleId,
FK_ReportsToUserId = request.ReportsToUserId
};
await uow.BeginAsync(ct);
try
{
await repo.AddAsync(user);
var authResult = await authHex.CallAsync("registerUser", new
{
userId = user.Id,
userName = request.Username,
email = request.Username,
fullname = request.FullName,
password = request.Password,
roleId = request.RoleId.ToString(),
userTypeId = "00000001-0000-0000-0000-200000000000",
sendCredentialsEmail = false
}, reference: user.Id.ToString(), ct: ct);
if (!authResult.Success)
{
await uow.RollbackAsync(ct);
throw new InvalidOperationException($"AuthHex registration failed: {authResult.Message}");
}
await uow.CommitAsync(ct);
}
catch
{
await uow.RollbackAsync(ct);
throw;
}
return ToResponse(user);
}
public async Task<UserResponse?> UpdateAsync(Guid id, UpdateUserRequest request, CancellationToken ct = default)
{
var user = await repo.GetByIdAsync(id);
if (user is null || !user.IsActive) return null;
user.FullName = request.FullName;
if (!string.IsNullOrWhiteSpace(request.Username))
user.Username = request.Username;
if (request.RoleId.HasValue)
user.FK_RoleId = request.RoleId.Value;
user.UpdatedAt = DateTime.Now;
await uow.BeginAsync(ct);
try
{
repo.Update(user);
var hasUsernameChange = !string.IsNullOrWhiteSpace(request.Username);
var hasRoleChange = request.RoleId.HasValue;
if (hasUsernameChange || hasRoleChange)
{
var payload = new Dictionary<string, object> { ["userId"] = user.Id.ToString() };
if (hasUsernameChange) payload["userName"] = request.Username!;
if (hasRoleChange) payload["roleCode"] = request.RoleId!.Value.ToString();
var authResult = await authHex.CallAsync("UpdateUser", payload, reference: user.Id.ToString(), ct: ct);
if (!authResult.Success)
{
await uow.RollbackAsync(ct);
throw new InvalidOperationException($"AuthHex update failed: {authResult.Message}");
}
}
if (!string.IsNullOrWhiteSpace(request.CurrentPassword) && !string.IsNullOrWhiteSpace(request.NewPassword))
{
var authResult = await authHex.CallAsync("ChangeUserPassword", new
{
userId = user.Id.ToString(),
currentPassword = request.CurrentPassword,
newPassword = request.NewPassword
}, reference: user.Id.ToString(), ct: ct);
if (!authResult.Success)
{
await uow.RollbackAsync(ct);
throw new InvalidOperationException($"AuthHex password change failed: {authResult.Message}");
}
}
await uow.CommitAsync(ct);
}
catch
{
await uow.RollbackAsync(ct);
throw;
}
return ToResponse(user);
}
public async Task<UserResponse?> AssignRoleAsync(Guid id, AssignUserRoleRequest request, CancellationToken ct = default)
{
return await UpdateAsync(id, new UpdateUserRequest(
FullName: (await repo.GetByIdAsync(id))?.FullName ?? string.Empty,
RoleId: request.RoleId), ct);
}
public async Task<bool> AssignScopeAsync(Guid id, AssignUserScopeRequest request, CancellationToken ct = default)
{
var user = await repo.GetByIdAsync(id);
if (user is null || !user.IsActive) return false;
await uow.BeginAsync(ct);
try
{
await repo.ReplaceRegionScopesAsync(id, request.RegionIds);
await repo.ReplaceRouteScopesAsync(id, request.RouteIds);
await repo.ReplaceStoreScopesAsync(id, request.StoreIds);
await uow.CommitAsync(ct);
}
catch
{
await uow.RollbackAsync(ct);
throw;
}
return true;
}
public async Task<bool> DeactivateAsync(Guid id, CancellationToken ct = default)
{
var user = await repo.GetByIdAsync(id);
if (user is null || !user.IsActive) return false;
await uow.BeginAsync(ct);
try
{
repo.Remove(user);
await uow.CommitAsync(ct);
}
catch
{
await uow.RollbackAsync(ct);
throw;
}
return true;
}
}