Add user profile fields and completion prompt
Build and Push Docker Image / build-and-push (push) Successful in 23s
Build and Push Docker Image / build-and-push (push) Successful in 23s
Added `FirstName`, `LastName`, and `Address` fields to `ApplicationUser` for extended user profiles. Updated `Index.razor` to include these fields in the profile form with validation. Introduced `ProfileCompletionService` to check profile completeness and added a prompt in `TopBar.razor` for incomplete profiles. Created migration `20260518213355_AddUserProfileFields` to update the database schema. Updated `RegistryService` to use new fields for user display names. Registered `ProfileCompletionService` and `DbContextFactory` in `Program.cs`. Styled the profile completion banner in `TopBar.razor.css`.
This commit is contained in:
@@ -95,18 +95,22 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var usersById = await applicationDbContext.Users
|
||||
var users = await applicationDbContext.Users
|
||||
.Where(x => admins.Contains(x.Id))
|
||||
.Select(x => new { x.Id, x.Email })
|
||||
.ToDictionaryAsync(x => x.Id, x => x.Email, cancellationToken)
|
||||
.Select(x => new { x.Id, x.Email, x.FirstName, x.LastName })
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var usersById = users.ToDictionary(
|
||||
x => x.Id,
|
||||
x => BuildUserDisplayName(x.FirstName, x.LastName, x.Email, x.Id));
|
||||
|
||||
return admins
|
||||
.Select(userId => new RegistryAdminDisplayModel
|
||||
{
|
||||
UserId = userId,
|
||||
DisplayName = usersById.TryGetValue(userId, out var email) && !string.IsNullOrWhiteSpace(email)
|
||||
? email
|
||||
DisplayName = usersById.TryGetValue(userId, out var displayName)
|
||||
? displayName
|
||||
: userId
|
||||
})
|
||||
.ToList();
|
||||
@@ -180,12 +184,16 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli
|
||||
userIds.Add(contribution.UserId);
|
||||
}
|
||||
|
||||
var usersById = await applicationDbContext.Users
|
||||
var users = await applicationDbContext.Users
|
||||
.Where(x => userIds.Contains(x.Id))
|
||||
.Select(x => new { x.Id, x.Email })
|
||||
.ToDictionaryAsync(x => x.Id, x => x.Email ?? x.Id, cancellationToken)
|
||||
.Select(x => new { x.Id, x.Email, x.FirstName, x.LastName })
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var usersById = users.ToDictionary(
|
||||
x => x.Id,
|
||||
x => BuildUserDisplayName(x.FirstName, x.LastName, x.Email, x.Id));
|
||||
|
||||
var purchasesByItemId = purchases
|
||||
.GroupBy(x => x.RegistryItemId)
|
||||
.ToDictionary(g => g.Key, g => g.ToList());
|
||||
@@ -422,12 +430,16 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli
|
||||
userIds.Add(contribution.UserId);
|
||||
}
|
||||
|
||||
var usersById = await applicationDbContext.Users
|
||||
var users = await applicationDbContext.Users
|
||||
.Where(x => userIds.Contains(x.Id))
|
||||
.Select(x => new { x.Id, x.Email })
|
||||
.ToDictionaryAsync(x => x.Id, x => x.Email ?? x.Id, cancellationToken)
|
||||
.Select(x => new { x.Id, x.Email, x.FirstName, x.LastName })
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var usersById = users.ToDictionary(
|
||||
x => x.Id,
|
||||
x => BuildUserDisplayName(x.FirstName, x.LastName, x.Email, x.Id));
|
||||
|
||||
var purchasesByItemId = purchases
|
||||
.GroupBy(x => x.RegistryItemId)
|
||||
.ToDictionary(g => g.Key, g => g.ToList());
|
||||
@@ -508,12 +520,16 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli
|
||||
userIds.Add(contribution.UserId);
|
||||
}
|
||||
|
||||
var usersById = await applicationDbContext.Users
|
||||
var users = await applicationDbContext.Users
|
||||
.Where(x => userIds.Contains(x.Id))
|
||||
.Select(x => new { x.Id, x.Email })
|
||||
.ToDictionaryAsync(x => x.Id, x => x.Email ?? x.Id, cancellationToken)
|
||||
.Select(x => new { x.Id, x.Email, x.FirstName, x.LastName })
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
var usersById = users.ToDictionary(
|
||||
x => x.Id,
|
||||
x => BuildUserDisplayName(x.FirstName, x.LastName, x.Email, x.Id));
|
||||
|
||||
return new RegistryItemEditModel
|
||||
{
|
||||
Id = item.Id,
|
||||
@@ -907,4 +923,20 @@ internal sealed class RegistryService(RegistryDbContext registryDbContext, Appli
|
||||
var fallback = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString("N")))).Substring(0, 16).ToLowerInvariant();
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private static string BuildUserDisplayName(string? firstName, string? lastName, string? email, string userId)
|
||||
{
|
||||
var fullName = $"{firstName} {lastName}".Trim();
|
||||
if (!string.IsNullOrWhiteSpace(fullName))
|
||||
{
|
||||
return fullName;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(email))
|
||||
{
|
||||
return email;
|
||||
}
|
||||
|
||||
return userId;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user