diff --git a/Api.SeaHavenIndustries.Tests/TeamMemberServiceTests.cs b/Api.SeaHavenIndustries.Tests/TeamMemberServiceTests.cs index 04024f6..d005ed6 100644 --- a/Api.SeaHavenIndustries.Tests/TeamMemberServiceTests.cs +++ b/Api.SeaHavenIndustries.Tests/TeamMemberServiceTests.cs @@ -216,6 +216,57 @@ public sealed class TeamMemberServiceTests overrides.Verify(data => data.SetOverridesAsync(user.Id, It.Is>(value => value["createSites"] == UserPermissionState.Deny), It.IsAny()), Times.Once); } + [Fact] + public async Task Update_SavesUnchangedNameWithoutDuplicatingRoleLikeLastName() + { + var service = NewService( + out var userManager, + out var roleManager, + out var areas, + out _, + out var userData, + out var permissions); + var user = new ApplicationUser + { + Id = "admin", + FirstName = "Legacy", + LastName = "Manager", + Email = "legacy@example.com", + Color = "#F59E0B", + UniqueName = "Active" + }; + userManager.Setup(manager => manager.FindByIdAsync(user.Id)).ReturnsAsync(user); + userManager.Setup(manager => manager.GetRolesAsync(user)).ReturnsAsync(new List { "Admin" }); + userManager.Setup(manager => manager.FindByEmailAsync(user.Email!)).ReturnsAsync(user); + roleManager.Setup(manager => manager.RoleExistsAsync("Admin")).ReturnsAsync(true); + areas.Setup(data => data.GetForUserAsync(user.Id, It.IsAny())) + .ReturnsAsync(Array.Empty()); + permissions.Setup(data => data.GetProfileAsync(user.Id, It.IsAny(), It.IsAny())) + .ReturnsAsync(TeamPermissionResult.Success(new TeamPermissionProfileDTO + { + UserId = user.Id, + Permissions = Array.Empty() + })); + + var result = await service.UpdateAsync( + user.Id, + new UpdateTeamMemberRequestDTO + { + Name = "Legacy Manager", + Role = "Admin", + Color = "#F59E0B", + Email = user.Email + }, + Admin(), + CancellationToken.None); + + result.Success.Should().BeTrue(); + user.FirstName.Should().Be("Legacy"); + user.LastName.Should().Be("Manager"); + result.Member!.Name.Should().Be("Legacy Manager"); + userData.Verify(data => data.UpdateUserAsync(user, It.IsAny()), Times.Once); + } + [Fact] public async Task Update_LeavesOmittedOverridesUnchanged() { diff --git a/SeaHaven.Services/Implementation/TeamMemberService.cs b/SeaHaven.Services/Implementation/TeamMemberService.cs index aeeef94..8933bac 100644 --- a/SeaHaven.Services/Implementation/TeamMemberService.cs +++ b/SeaHaven.Services/Implementation/TeamMemberService.cs @@ -167,7 +167,7 @@ public sealed class TeamMemberService : ITeamMemberService if (roleError is not null) return OperationFailure(roleError); - user.FirstName = candidate.Name!.Trim(); + ApplyName(user, candidate.Name!.Trim()); user.Contact = candidate.Phone?.Trim(); user.PhoneNumber = candidate.Phone?.Trim(); user.Color = color; @@ -215,6 +215,24 @@ public sealed class TeamMemberService : ITeamMemberService return await OperationSuccessAsync(user, caller, cancellationToken); } + private static void ApplyName(ApplicationUser user, string fullName) + { + var current = $"{user.FirstName ?? ""} {user.LastName ?? ""}".Trim(); + if (string.Equals(fullName, current, StringComparison.Ordinal)) + return; + + var separator = fullName.IndexOf(' '); + if (separator < 0) + { + user.FirstName = fullName; + user.LastName = null; + return; + } + + user.FirstName = fullName[..separator].Trim(); + user.LastName = fullName[(separator + 1)..].Trim(); + } + private async Task EnsureRoleAsync(string role) { if (await _roleManager.RoleExistsAsync(role))