From ca59b747227958d5ec411646d65d47287e332b32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20Pilgaard=20Gr=C3=B8ndahl?= Date: Sun, 6 Aug 2023 14:45:39 +0200 Subject: [PATCH] chat 6/? I think --- .../Features/Chat/UserAutoComplete.razor | 26 +++++++++++- .../UserSearch/AddressAutoComplete.razor | 1 - .../Features/UserSearch/IUserSearchClient.cs | 3 ++ .../Features/UserSearch/UserSearchApi.cs | 17 ++++++++ .../Features/UserSearch/UserSearchService.cs | 41 +++++++++++++++++-- 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/src/web/Client/Features/Chat/UserAutoComplete.razor b/src/web/Client/Features/Chat/UserAutoComplete.razor index 560f80df..54697682 100644 --- a/src/web/Client/Features/Chat/UserAutoComplete.razor +++ b/src/web/Client/Features/Chat/UserAutoComplete.razor @@ -1,5 +1,29 @@ -TODO: Place user search here +@inject IUserSearchClient UserSearchClient + + + + @code { + private string? _searchString; + + private async Task> SearchForUsers(string arg1, CancellationToken arg2) + { + var searchResponse = await UserSearchClient.GetUsersWithAutoComplete(_searchString, arg2); + + return searchResponse.IsSuccessStatusCode + ? searchResponse.Content!.Select(response => response.ToString()) + : Array.Empty(); + } + } diff --git a/src/web/Client/Features/UserSearch/AddressAutoComplete.razor b/src/web/Client/Features/UserSearch/AddressAutoComplete.razor index 3b8fc1dc..d47fce71 100644 --- a/src/web/Client/Features/UserSearch/AddressAutoComplete.razor +++ b/src/web/Client/Features/UserSearch/AddressAutoComplete.razor @@ -39,5 +39,4 @@ Location = value; await LocationChanged.InvokeAsync(Location); } - } diff --git a/src/web/Client/Features/UserSearch/IUserSearchClient.cs b/src/web/Client/Features/UserSearch/IUserSearchClient.cs index 37eea589..0753ce38 100644 --- a/src/web/Client/Features/UserSearch/IUserSearchClient.cs +++ b/src/web/Client/Features/UserSearch/IUserSearchClient.cs @@ -7,4 +7,7 @@ public interface IUserSearchClient { [Get("/api/users/search")] Task> GetUsers(UserSearchFilter filter); + + [Get("/api/users/search/autocomplete")] + Task> GetUsersWithAutoComplete(string searchString); } diff --git a/src/web/Server/Features/UserSearch/UserSearchApi.cs b/src/web/Server/Features/UserSearch/UserSearchApi.cs index 8cbc78f5..b1434ccb 100644 --- a/src/web/Server/Features/UserSearch/UserSearchApi.cs +++ b/src/web/Server/Features/UserSearch/UserSearchApi.cs @@ -1,5 +1,6 @@ using Jordnaer.Server.Extensions; using Jordnaer.Shared; +using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; namespace Jordnaer.Server.Features.UserSearch; @@ -45,6 +46,22 @@ public static RouteGroupBuilder MapUserSearch(this IEndpointRouteBuilder routes) return users; }); + + group.MapGet("autocomplete", async Task, BadRequest>> ( + [FromServices] IUserSearchService userService, + [FromQuery] string searchString, + CancellationToken cancellationToken) => + { + if (string.IsNullOrEmpty(searchString)) + { + return TypedResults.BadRequest(); + } + + var users = await userService.GetUsersByNameAsync(searchString, cancellationToken); + + return TypedResults.Ok(users); + }); + return group; } } diff --git a/src/web/Server/Features/UserSearch/UserSearchService.cs b/src/web/Server/Features/UserSearch/UserSearchService.cs index cfe634cf..b07ff6ee 100644 --- a/src/web/Server/Features/UserSearch/UserSearchService.cs +++ b/src/web/Server/Features/UserSearch/UserSearchService.cs @@ -9,10 +9,14 @@ namespace Jordnaer.Server.Features.UserSearch; public interface IUserSearchService { Task GetUsersAsync(UserSearchFilter filter, CancellationToken cancellationToken); + Task GetUsersByNameAsync(string searchString, CancellationToken cancellationToken); } public class UserSearchService : IUserSearchService { + private static readonly List _emptyStringList = new(); + private static readonly List _emptyChildDtoList = new(); + private readonly ILogger _logger; private readonly JordnaerDbContext _context; private readonly IDataForsyningenClient _dataForsyningenClient; @@ -30,13 +34,42 @@ public UserSearchService( _options = options.Value; } + public async Task GetUsersByNameAsync(string searchString, CancellationToken cancellationToken) + { + + var users = _context.UserProfiles.AsQueryable(); + + users = ApplyNameFilter(searchString, users); + + var paginatedUsers = await users + .OrderBy(user => user.CreatedUtc) + .Take(10) + .Select(user => new UserDto + { + ProfilePictureUrl = user.ProfilePictureUrl, + UserName = user.UserName, + FirstName = user.FirstName, + LastName = user.LastName, + ZipCode = user.ZipCode, + City = user.City, + Children = _emptyChildDtoList, + LookingFor = _emptyStringList + }) + .AsNoTracking() + .ToListAsync(cancellationToken); + + int totalCount = await users.AsNoTracking().CountAsync(cancellationToken); + + return new UserSearchResult { TotalCount = totalCount, Users = paginatedUsers }; + } + public async Task GetUsersAsync(UserSearchFilter filter, CancellationToken cancellationToken) { // TODO: Convert to Dapper var users = _context.UserProfiles.AsQueryable(); users = ApplyChildFilters(filter, users); - users = ApplyNameFilter(filter, users); + users = ApplyNameFilter(filter.Name, users); users = ApplyLookingForFilter(filter, users); (users, bool isOrdered) = await ApplyLocationFilterAsync(filter, users); @@ -152,11 +185,11 @@ private static IQueryable ApplyLookingForFilter(UserSearchFilter fi return users; } - private static IQueryable ApplyNameFilter(UserSearchFilter filter, IQueryable users) + private static IQueryable ApplyNameFilter(string? filter, IQueryable users) { - if (!string.IsNullOrWhiteSpace(filter.Name)) + if (!string.IsNullOrWhiteSpace(filter)) { - string trimmedNameFilter = new(filter.Name.Where(c => !char.IsWhiteSpace(c)).ToArray()); + string trimmedNameFilter = new(filter.Where(c => !char.IsWhiteSpace(c)).ToArray()); users = users.Where(user => !string.IsNullOrEmpty(user.SearchableName) && EF.Functions.Like(user.SearchableName, $"%{trimmedNameFilter}%"));