From 8b544ca00928f703b0939e55f70c210e4bccba7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C2=96=C2=96AsTroLog?= Date: Fri, 17 Nov 2023 07:30:23 +0000 Subject: [PATCH] fix bags and connect product search --- .../Models/Messages.cs | 17 +- .../Network/ApiClient.cs | 7 +- .../Pages/Chat.razor | 89 +++++--- .../Pages/Chat.razor.cs | 191 ++++++++++++++---- .../Pages/Chat.razor.css | 4 +- .../Pages/Index.razor | 21 +- .../Pages/Index.razor.cs | 65 +++++- .../Shared/NavMenu.razor | 115 +++++++++-- .../Shared/NavMenu.razor.cs | 30 ++- .../Shared/NavMenu.razor.css | 99 +++++++-- 10 files changed, 511 insertions(+), 127 deletions(-) diff --git a/ShoppingAssistantWebClient.Web/Models/Messages.cs b/ShoppingAssistantWebClient.Web/Models/Messages.cs index 9cbed36..5fa992d 100644 --- a/ShoppingAssistantWebClient.Web/Models/Messages.cs +++ b/ShoppingAssistantWebClient.Web/Models/Messages.cs @@ -3,12 +3,21 @@ public class Messages { - public required string Id { get; set; } + public string Id { get; set; } - public required string Text { get; set; } + public string Text { get; set; } - public required string Role { get; set; } + public string Role { get; set; } + + public string CreatedById { get; set; } + + + public Messages() + { - public required string CreatedById { get; set; } } + + } + + } diff --git a/ShoppingAssistantWebClient.Web/Network/ApiClient.cs b/ShoppingAssistantWebClient.Web/Network/ApiClient.cs index d87bb3a..a4a6f24 100644 --- a/ShoppingAssistantWebClient.Web/Network/ApiClient.cs +++ b/ShoppingAssistantWebClient.Web/Network/ApiClient.cs @@ -99,7 +99,7 @@ public class ApiClient public async IAsyncEnumerable GetServerSentEventStreamed(string url, Object obj, CancellationToken cancellationToken) { await SetAuthenticationAsync(); - + var count = 0; // var requestUrl = $"{_httpClient.BaseAddress}{url}"; var response = await _httpClient.PostAsJsonAsync(requestUrl, obj); using var responseStream = await response.Content.ReadAsStreamAsync(); @@ -109,9 +109,14 @@ public class ApiClient while (!cancellationToken.IsCancellationRequested) { var jsonChunk = await reader.ReadLineAsync(cancellationToken); + count += 1; // + if (count >=5 ){ // + break; // + }; // if (jsonChunk == null) continue; if (jsonChunk.StartsWith("event: ")) { + count = 0; // var type = jsonChunk.Substring("event: ".Length); switch(type) { diff --git a/ShoppingAssistantWebClient.Web/Pages/Chat.razor b/ShoppingAssistantWebClient.Web/Pages/Chat.razor index 939c8e8..8cf37c6 100644 --- a/ShoppingAssistantWebClient.Web/Pages/Chat.razor +++ b/ShoppingAssistantWebClient.Web/Pages/Chat.razor @@ -1,8 +1,9 @@ @page "/chat/{chatId}" @inject IHttpClientFactory ClientFactory +@inject IJSRuntime JSRuntime -Gift for Jessica +@name
@@ -16,30 +17,35 @@
-
+
@name
-
Gift for Jessica
+
    - @if(!isLoading && Messages!=null){ + @if (!isLoading && Messages != null) + { - @foreach (var item in Messages){ + @foreach (var item in Messages) + { - if(item.Role!="User"){ + if (item.Role != "User") + { -
  • -

    @item.Text

    -
  • +
  • +

    @item.Text

    +
  • - }else{ + } + else + { -
  • -

    @item.Text

    -
  • +
  • +

    @item.Text

    +
  • - } + } } } @@ -52,21 +58,27 @@
    -
    Several possible options
    + @if (Suggestion.Count != 0) + { -
    +
    Several possible options
    -
    - HDMI -
    -
    - VGA -
    -
    - DisplayPort -
    +
    -
    + + + @foreach (var item in Suggestion) + { + +
    + @item +
    + } + + + +
    + }
    @@ -84,8 +96,15 @@ @code { @@ -100,8 +119,22 @@ { if (e.Code == "Enter" || e.Code == "NumpadEnter") { - AddNewMessage(); + AddNewMessage(); } } - + + private ElementReference chatMessageRef; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + await JSRuntime.InvokeVoidAsync("scrollToBottom", chatMessageRef); + await JSRuntime.InvokeVoidAsync("scrollToBottom", chatMessageRef); + await JSRuntime.InvokeVoidAsync("scrollToBottom", chatMessageRef); + } + + + private void ClickOption(string item) { + inputValue = item; + } + } \ No newline at end of file diff --git a/ShoppingAssistantWebClient.Web/Pages/Chat.razor.cs b/ShoppingAssistantWebClient.Web/Pages/Chat.razor.cs index 6fbee2d..17b0ddf 100644 --- a/ShoppingAssistantWebClient.Web/Pages/Chat.razor.cs +++ b/ShoppingAssistantWebClient.Web/Pages/Chat.razor.cs @@ -3,7 +3,9 @@ using ShoppingAssistantWebClient.Web.Models; using GraphQL; using Newtonsoft.Json; using ShoppingAssistantWebClient.Web.Network; - +using ShoppingAssistantWebClient.Web.Models.Input; +using ShoppingAssistantWebClient.Web.Models.Enums; +using System.Text.RegularExpressions; namespace ShoppingAssistantWebClient.Web.Pages; public partial class Chat : ComponentBase @@ -11,10 +13,20 @@ public partial class Chat : ComponentBase [Inject] private ApiClient _apiClient { get; set; } + [Inject] + private NavigationManager Navigation { get; set; } public List Messages { get; set; } + public List Suggestion { get; set; } = new List(); + + public Messages Message { get; set; } + + private CancellationTokenSource cancelTokenSource; + + private MessageCreateDto messageCreateDto; public bool isLoading = true; private string inputValue = ""; + private string name = ""; protected override async Task OnInitializedAsync() { await LoadMessages(); @@ -23,12 +35,34 @@ public partial class Chat : ComponentBase private async Task LoadMessages() { + string wishlistId = chatId; + + Suggestion.Add("123"); + Suggestion.Add("456"); + Suggestion.Add("145623"); + + var request = new GraphQLRequest + { + Query = @"query PersonalWishlist( $wishlistId: String!) { + personalWishlist(wishlistId: $wishlistId) { + name + } + }", + + Variables = new + { + wishlistId, + } + }; + + var response = await _apiClient.QueryAsync(request); + var responseData = response.Data; + name = responseData.personalWishlist.name; isLoading = true; int pageNumber = 1; - string wishlistId = chatId; - var request = new GraphQLRequest + request = new GraphQLRequest { Query = @"query MessagesPageFromPersonalWishlist($wishlistId: String!, $pageNumber: Int!, $pageSize: Int!) { messagesPageFromPersonalWishlist( wishlistId: $wishlistId, pageNumber: $pageNumber, pageSize: $pageSize) @@ -46,12 +80,12 @@ public partial class Chat : ComponentBase { wishlistId, pageNumber, - pageSize = 20 + pageSize = 200 } }; try{ - var response = await _apiClient.QueryAsync(request); - var responseData = response.Data; + response = await _apiClient.QueryAsync(request); + responseData = response.Data; var jsonCategoriesResponse = JsonConvert.SerializeObject(responseData.messagesPageFromPersonalWishlist.items); this.Messages = JsonConvert.DeserializeObject>(jsonCategoriesResponse); Messages.Reverse(); @@ -60,42 +94,127 @@ public partial class Chat : ComponentBase }catch{ } - - } - private async Task AddNewMessage() - { + /* + try{ - isLoading = true; - var pageNumber = 1; - var wishlistId = chatId; - var text = inputValue; - inputValue=""; - var request = new GraphQLRequest - { - Query = @"mutation AddMessageToPersonalWishlist($wishlistId: String!, $text: String!) { - addMessageToPersonalWishlist(wishlistId: $wishlistId, dto: { text: $text }) { - id - text - role - createdById - } - } - ", - Variables = new - { - wishlistId, - text + pageNumber = 0; + + do{ + pageNumber++; + + request = new GraphQLRequest + { + Query = @"query MessagesPageFromPersonalWishlist($wishlistId: String!, $pageNumber: Int!, $pageSize: Int!) { + messagesPageFromPersonalWishlist( wishlistId: $wishlistId, pageNumber: $pageNumber, pageSize: $pageSize) + { + items { + id + text + role + createdById + } + totalPages + } + }", + + Variables = new + { + wishlistId, + pageNumber, + pageSize = 1 + } + }; + + response = await _apiClient.QueryAsync(request); + responseData = response.Data; + var jsonCategoriesResponse = JsonConvert.SerializeObject(responseData.messagesPageFromPersonalWishlist.items); + if(pageNumber == 1){ + Messages = JsonConvert.DeserializeObject>(jsonCategoriesResponse); + }else{ + Message = JsonConvert.DeserializeObject>(jsonCategoriesResponse); + Messages.InsertRange(0, Message); } - }; + + + // Messages.Reverse(); + totalPages = responseData.messagesPageFromPersonalWishlist.totalPages; + isLoading = false; + StateHasChanged(); + }while(pageNumberNew Chat
    @@ -87,6 +86,18 @@ choose = "Product"; } + function myJavaScriptFunction(wishlistId) { + + UpdateMenu(wishlistId); + + } + + + + + + + document.getElementById('choose_gift').addEventListener('click', switchGift); document.getElementById('choose_product').addEventListener('click', switchProduct); @@ -102,4 +113,12 @@ private void Сhoose_gift() { selectedChoice = "Gift"; } + + private async Task UpdateSideMenu(string wishlistId) + { + + await JSRuntime.InvokeVoidAsync("myJavaScriptFunction", wishlistId); + + } + } diff --git a/ShoppingAssistantWebClient.Web/Pages/Index.razor.cs b/ShoppingAssistantWebClient.Web/Pages/Index.razor.cs index 492da25..cfa3f07 100644 --- a/ShoppingAssistantWebClient.Web/Pages/Index.razor.cs +++ b/ShoppingAssistantWebClient.Web/Pages/Index.razor.cs @@ -1,11 +1,12 @@ using Microsoft.AspNetCore.Components; +using ShoppingAssistantWebClient.Web.Models; using ShoppingAssistantWebClient.Web.Models.ProductSearch; using ShoppingAssistantWebClient.Web.Models.Input; using GraphQL; using Newtonsoft.Json; using ShoppingAssistantWebClient.Web.Network; using System; - +using Microsoft.JSInterop; namespace ShoppingAssistantWebClient.Web.Pages { @@ -15,7 +16,11 @@ namespace ShoppingAssistantWebClient.Web.Pages [Inject] private ApiClient _apiClient { get; set; } [Inject] + private NavigationManager Navigation { get; set; } + [Inject] + protected IJSRuntime JSRuntime { get; set; } + private MessageCreateDto messageCreateDto; private CancellationTokenSource cancelTokenSource; @@ -26,7 +31,7 @@ namespace ShoppingAssistantWebClient.Web.Pages private async Task CreateNewChat() { - try + try { if (string.IsNullOrWhiteSpace(inputValue)) { @@ -36,7 +41,7 @@ namespace ShoppingAssistantWebClient.Web.Pages isLoading = true; messageCreateDto = new MessageCreateDto { Text = inputValue }; var type = selectedChoice; - var firstMessageText = $"[Question] What are you looking for? [Suggestions] " + inputValue; + var firstMessageText = $"What are you looking for?"; var request = new GraphQLRequest { @@ -56,20 +61,68 @@ namespace ShoppingAssistantWebClient.Web.Pages var response = await _apiClient.QueryAsync(request); var responseData = response.Data; var chatId = responseData?.startPersonalWishlist?.id; - isLoading = false; - var url = $"/chat/{chatId}"; + string wishlistId1 = chatId; + await UpdateSideMenu(wishlistId1); + + var text = inputValue; +/* + inputValue=""; + request = new GraphQLRequest + { + Query = @"mutation AddMessageToPersonalWishlist($wishlistId: String!, $text: String!) { + addMessageToPersonalWishlist(wishlistId: $wishlistId, dto: { text: $text }) { + id + text + role + createdById + } + } + ", + + Variables = new + { + wishlistId =chatId, + text + } + }; + + await _apiClient.QueryAsync(request); +*/ + cancelTokenSource = new CancellationTokenSource(); var cancellationToken = cancelTokenSource.Token; var serverSentEvent = _apiClient.GetServerSentEventStreamed($"ProductsSearch/search/{chatId}", messageCreateDto, cancellationToken); - Navigation.NavigateTo(url); + await foreach (var sseEvent in serverSentEvent.WithCancellation(cancellationToken)) { // Handle each ServerSentEvent as needed Console.WriteLine($"Received SSE Event: {sseEvent.Event}, Data: {sseEvent.Data}"); } + string wishlistId = chatId; + + request = new GraphQLRequest + { + Query = @"mutation GenerateNameForPersonalWishlist($wishlistId: String!) { + generateNameForPersonalWishlist(wishlistId: $wishlistId) { + id + name + } + }", + Variables = new + { + wishlistId + + } + }; + + response = await _apiClient.QueryAsync(request); + + var url = $"/chat/{chatId}"; + Navigation.NavigateTo(url); + } catch (Exception ex) { diff --git a/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor b/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor index 08dd11c..aecb358 100644 --- a/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor +++ b/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor @@ -1,5 +1,9 @@ @using Models.GlobalInstances +@using System.Linq +@using Microsoft.AspNetCore.Components +@using Microsoft.JSInterop @inject NavigationManager Navigation +@inject IJSRuntime JSRuntime;
    @@ -16,7 +20,8 @@ -
    + +
    @@ -29,15 +34,15 @@ @if(!isLoading){ - @foreach (var item in Wishlists) + @foreach (var item in Wishlists) { -
    -
    @item.Name
    - Delete wishlist - Card open + +
    +
    @item.Name
    + Delete wishlist + Card open
    } - }
    @@ -81,31 +86,99 @@ } document.getElementById('button_close').addEventListener('click', changetyle); +/* + window.getScrollTop = function (element) { + return element.scrollTop; + }; + + window.getOffsetHeight = function (element) { + return element.offsetHeight; + }; + + window.getScrollHeight = function (element) { + return element.scrollHeight; + }; + + window.setScrollTop = function (element, scrollTop) { + element.scrollTop = scrollTop; + }; +*/ + + + + @code { + [Parameter] public string chatId { get; set; } + + + private string selectedWishlistId; + + + private static NavMenu _app; + + public NavMenu () + { + _app = this; + + } + + [JSInvokable] + public static void Update(string wishlistId) + { + _app.LoadMenus(1,200); + _app.selectedWishlistId=wishlistId; + } + private void RedirectToPage(string itemId) { - var url = $"/chat/{itemId}"; - Navigation.NavigateTo(url); - } + _app.selectedWishlistId = itemId; + var url = $"/chat/{itemId}"; + Navigation.NavigateTo(url); + } private void RedirectToNewChat() { - var url = $"/"; - Navigation.NavigateTo(url); - } + var url = $"/"; + Navigation.NavigateTo(url); + } private void RedirectToCard(string itemId) { - var url = $"/chat/{itemId}/cart"; - Navigation.NavigateTo(url); - } + var url = $"/chat/{itemId}/cart"; + Navigation.NavigateTo(url); + } private async void DeleteWishlist(string itemId) { await DeleteWish(itemId); - - } - public void UpdateSideMenu() - { - StateHasChanged(); } +/* + private int savedScrollTop = 0; + + private ElementReference wishlishtRef; + + private async Task OnScroll() + { + var scrollTop = await JSRuntime.InvokeAsync("getScrollTop", wishlishtRef); + var offsetHeight = await JSRuntime.InvokeAsync("getOffsetHeight", wishlishtRef); + var scrollHeight = await JSRuntime.InvokeAsync("getScrollHeight", wishlishtRef); + + if (scrollTop + offsetHeight > scrollHeight - 100) + { + savedScrollTop = scrollTop; + currentPage++; + await LoadMenus(currentPage, pageSize); + await InvokeAsync(() => JSRuntime.InvokeVoidAsync("setScrollTop", wishlishtRef, savedScrollTop)); + } + } +*/ + + } diff --git a/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor.cs b/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor.cs index 39d54a4..d3bd0a5 100644 --- a/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor.cs +++ b/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor.cs @@ -14,14 +14,20 @@ namespace ShoppingAssistantWebClient.Web.Shared public List Wishlists { get; set; } public bool isLoading = true; + public int pageSize { get; set; } + public int currentPage { get; set; } + protected override async Task OnInitializedAsync() { - await LoadMenus(); + pageSize = 200; + currentPage = 1; + Wishlists = new List(); + await LoadMenus(currentPage, pageSize); + } - private async Task LoadMenus() + public async Task LoadMenus(int pageNumber, int pageSize ) { isLoading = true; - var pageNumber = 1; var request = new GraphQLRequest { Query = @"query PersonalWishlistsPage( $pageNumber: Int!, $pageSize: Int!) { @@ -36,17 +42,19 @@ namespace ShoppingAssistantWebClient.Web.Shared Variables = new { pageNumber, - pageSize = 40, + pageSize, } }; - var response = await _apiClient.QueryAsync(request); - var responseData = response.Data; - var jsonCategoriesResponse = JsonConvert.SerializeObject(responseData.personalWishlistsPage.items); - this.Wishlists = JsonConvert.DeserializeObject>(jsonCategoriesResponse); - isLoading = false; + var response = await _apiClient.QueryAsync(request); + var responseData = response.Data; + var jsonCategoriesResponse = JsonConvert.SerializeObject(responseData.personalWishlistsPage.items); + this.Wishlists.AddRange(JsonConvert.DeserializeObject>(jsonCategoriesResponse)); + Wishlists.Reverse(); + isLoading = false; + StateHasChanged(); } - + protected async Task DeleteWish(string wishlistId) { var request = new GraphQLRequest @@ -65,7 +73,7 @@ namespace ShoppingAssistantWebClient.Web.Shared }; var response = await _apiClient.QueryAsync(request); - await LoadMenus(); + await LoadMenus(currentPage, pageSize); } } diff --git a/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor.css b/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor.css index 091f52e..bc5c52c 100644 --- a/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor.css +++ b/ShoppingAssistantWebClient.Web/Shared/NavMenu.razor.css @@ -1,10 +1,10 @@ - .left_frame { position: relative; height: 100%; width: 100%; transition: 1s; } + .logo { height: 5em; position: relative; @@ -12,26 +12,35 @@ align-items: center; padding-bottom: 1.5%; } + .menu { position: absolute; width: 100%; - top: 5em; + top: 5em; bottom: 0; border: 1.5px solid; border-color: #0052CC; border-radius: 0.6em; padding-top: 1.5%; } + .elements_wishlisht { - position: absolute; - overflow-y: auto; top: 2.43em; width: 100%; - bottom: 4em; + bottom: 3.8em; padding-left: 1.25em; padding-right: 1.25em; + padding-bottom: 3.8em; } + +.wishlist_names { + overflow-y: auto; + position: relative; + width: 100%; + height:100%; +} + .info_user { position: absolute; display: flex; @@ -46,6 +55,7 @@ padding-right: 1.25em; border-top: 1px solid #0165FF; } + .logo_name { padding-top: 0.5em; padding-left: 0.3em; @@ -56,11 +66,13 @@ font-weight: 600; overflow: hidden; } + .logo img { float: left; height: 3.25em; width: 3.25em; } + .wishlist_name { padding-left: 0.7em; padding-right: 5em; @@ -68,10 +80,11 @@ white-space: nowrap; overflow: hidden; position: absolute; - height: 2.5em; + height: 2.5em; line-height: 2.5em; cursor: pointer; } + .cont_wishlist { margin-top: 0.4375em; margin-bottom: 0.4375em; @@ -79,23 +92,64 @@ border-radius: 0.6em; font-size: 1.1em; width: 100%; - height:2.5em; + height: 2.5em; } + .cont_wishlist:hover { + background-color: #e6e6e6; transition: 0.2s; } -.cont_wishlist:hover .button_delete_chat{ + +.cont_wishlist:hover .button_delete_chat { visibility: visible; } -.cont_wishlist:hover .button_open_card{ + +.cont_wishlist:hover .button_open_card { visibility: visible; - + } + +.selected_wishlist { + margin-top: 0.4375em; + margin-bottom: 0.4375em; + color: black; + border-radius: 0.6em; + font-size: 1.1em; + width: 100%; + height: 2.5em; + background-color: #e6e6e6; + transition: 0.2s; + +} + +.sel_del { + visibility: visible; + cursor: pointer; + margin-top: 0.55em; + margin-right: 1em; + float: right; + position: relative; + + +} + +.selected_card{ + cursor: pointer; + position: relative; + z-index: 999; + margin-top: 0.55em; + margin-right: 1em; + float: right; + visibility: visible; + height: 1.4em; + width: 1.5em; +} + .button_delete_chat { cursor: pointer; - margin-top: 0.55em; + margin-top: 0.55em; margin-right: 1em; float: right; position: relative; @@ -103,6 +157,7 @@ height: 1.4em; width: 1.4em; } + .button_open_card { cursor: pointer; position: relative; @@ -114,14 +169,17 @@ height: 1.4em; width: 1.5em; } -.elements_wishlisht::-webkit-scrollbar { + +.wishlist_names::-webkit-scrollbar { border-radius: 20px; width: 0.2em; } -.elements_wishlisht::-webkit-scrollbar-thumb { - background-color: #0052CC; /* Колір позиції покажчика */ - border-radius: 10px; /* Закруглення країв позиції покажчика */ +.wishlist_names::-webkit-scrollbar-thumb { + background-color: #0052CC; + /* Колір позиції покажчика */ + border-radius: 10px; + /* Закруглення країв позиції покажчика */ width: 0.2em; } @@ -131,10 +189,11 @@ border-radius: 0.6em; font-size: 1.2em; width: 100%; - height:2.5em; + height: 2.5em; cursor: pointer; line-height: 2.5em; } + .add_chat div { justify-content: center; align-items: center; @@ -143,11 +202,12 @@ text-decoration: none; color: #FFFFFF; } + .plus { position: absolute; right: 1em; top: -0.1em; - font-size: 1.9em; + font-size: 1.9em; } .user_name { @@ -156,12 +216,14 @@ justify-content: center; align-items: center; } + .info_user img { float: left; border-radius: 50%; width: 2.3em; height: 2.3em; } + .button_close_menu { position: relative; width: 1.43em; @@ -171,6 +233,7 @@ margin-top: 0.5em; margin-right: 1.30em; } + .button_close_menu span { width: 20px; height: 1.5px; @@ -180,9 +243,11 @@ transform: translate(-50%, -50%); background-color: #4E4E4E; } + .button_close_menu span:nth-of-type(2) { top: calc(50% - 5px); } + .button_close_menu span:nth-of-type(3) { top: calc(50% + 5px); } \ No newline at end of file