This commit is contained in:
mmrbnjd
2025-10-24 14:26:20 +03:30
parent 58975ce589
commit 214112a92a
21 changed files with 559 additions and 2893 deletions

View File

@@ -1,5 +1,4 @@
@page "/UserCP/{CompanyID:int}"
@page "/UserCP/{CompanyID:int}/{ChatID:int?}"
@using Common.Dtos.Company
@using Common.Dtos.Conversation
@using Common.Dtos.Group
@@ -13,6 +12,7 @@
{
<PageTitle>گفتگو با @CompanyInfo?.FullName</PageTitle>
}
@implements IAsyncDisposable
@inject NavigationManager NavigationManager
@inject ChatService ChatService
@@ -27,22 +27,23 @@
@inject ToastService toastService
@inject HttpClient _Http;
@layout UserPanelLayout
<ConfirmDialog @ref="dialog" />
<div class="container-fluid">
<div class="row" style="height:85vh">
@if (IsEndFirstProcess)
{
@if (IsLogin)
if (string.IsNullOrEmpty(Error))
{
<div class="col-md-12 d-flex flex-column" id="B">
<div class="input-group">
@if (LastOpenChat != null)
@if (Chat != null)
{
<p type="text" class="form-control fw-bold text-primary" style="border:none;align-self: center;" aria-describedby="basic-addon1">@ExperYou</p>
}
<div class="d-flex gap-2 ms-auto">
@if (LastOpenChat != null)
@if (Chat != null)
{
<Button Color="ButtonColor.Success" Size=ButtonSize.ExtraSmall Outline="true" @onclick="NewChat" Class="new-conversation-btn">
@@ -56,15 +57,15 @@
</div>
<!-- B1: Chat area -->
<div class="flex-fill chat-area-container" id="B1">
@if (LastOpenChat != null && LastOpenChat.Responses != null)
@if (Chat != null && Chat.Responses != null)
{
<div class="chat-container p-3">
@{
bool target = false;
}
@foreach (var msg in LastOpenChat?.Responses)
@foreach (var msg in Chat?.Responses)
{
@if (!target && ((!msg.IsRead && msg.Type != Common.Enums.ConversationType.UE) || LastOpenChat.Responses.Last() == msg))
@if (!target && ((!msg.IsRead && msg.Type != Common.Enums.ConversationType.UE) || Chat.Responses.Last() == msg))
{
target = true;
<div id="target" class="chat-separator">
@@ -77,8 +78,8 @@
</div>
}
<div class="d-flex mb-2 @(msg.Type!=Common.Enums.ConversationType.UE ? "justify-content-end" : "justify-content-start")">
<div class="chat-bubble @(msg.Type!=Common.Enums.ConversationType.UE ? "chat-mine": "chat-other")" data-id="@msg.ID">
<div class="d-flex mb-2 @(msg.Type != Common.Enums.ConversationType.UE ? "justify-content-end" : "justify-content-start")">
<div class="chat-bubble @(msg.Type != Common.Enums.ConversationType.UE ? "chat-mine" : "chat-other")" data-id="@msg.ID">
@if (msg.FileContent != null && msg.FileContent.Length > 0 && !string.IsNullOrWhiteSpace(msg.FileType))
{
@if (msg.FileType.StartsWith("image/"))
@@ -137,10 +138,10 @@
<div class="groups-container mt-4">
<h6 class="text-center mb-3 text-muted">انتخاب گروه:</h6>
<div class="groups-grid">
@foreach (var group in CompanyGroups.Where(w=>w.Available))
@foreach (var group in CompanyGroups.Where(w => w.Available))
{
<div class="group-card @(GroupID == group.ID ? "selected" : "")"
@onclick="() => SelectGroup(group.ID)">
@onclick="() => SelectGroup(group.ID)">
<div class="group-card-content">
@if (group.img == null || group.img.Length == 0)
{
@@ -163,7 +164,7 @@
</div>
@if (CompanyInfo != null && (LastOpenChat == null || (LastOpenChat != null && LastOpenChat.status != Common.Enums.ConversationStatus.Finished && LastOpenChat.Responses != null)))
@if (CompanyInfo != null && (Chat == null || (Chat != null && Chat.status != Common.Enums.ConversationStatus.Finished && Chat.Responses != null)))
{
<!-- B2: Message input -->
<div class="message-input-container" id="B2">
@@ -175,13 +176,12 @@
</Button>
<!-- Audio Recording Button -->
<Button Color="@(IsRecording ? ButtonColor.Danger : ButtonColor.Secondary)"
Size=ButtonSize.Small
Outline="true"
@onclick="ToggleAudioRecording"
class=@($"audio-btn {(IsRecording ? "recording" : "")}")
title="@(IsRecording ? "توقف ضبط" : "ضبط صدا")"
>
<Button Color="@(IsRecording? ButtonColor.Danger: ButtonColor.Secondary)"
Size=ButtonSize.Small
Outline="true"
@onclick="ToggleAudioRecording"
class=@($"audio-btn {(IsRecording ? "recording" : "")}")
title="@(IsRecording ? "توقف ضبط" : "ضبط صدا")">
@if (IsRecording)
{
<Icon Name="IconName.StopCircle" Class="recording-pulse" />
@@ -235,7 +235,7 @@
</div>
@if (LastOpenChat!=null && LastOpenChat.status == Common.Enums.ConversationStatus.InProgress)
@if (Chat != null && Chat.status == Common.Enums.ConversationStatus.InProgress)
{
<Button Color="ButtonColor.Danger" Size=ButtonSize.ExtraSmall Outline="true" @onclick="CloseChat" Class="finish-conversation-btn">
<Icon Name="IconName.Escape" Class="me-1" /> اتمام گفتگو
@@ -243,23 +243,25 @@
}
}
@if (LastOpenChat.status == Common.Enums.ConversationStatus.Finished)
@if (Chat?.status == Common.Enums.ConversationStatus.Finished)
{
<p style="color: red;text-align: center;font-weight: bold;">این گفتگو به پایان رسیده</p>
}
</div>
}
else
{
<div class="d-flex justify-content-center align-items-center" style="height: 100%;">
<div class="login-container p-4 bg-white rounded shadow-sm" style="max-width: 400px; width: 100%;">
<div class="text-center mb-4">
<h4 class="text-primary mb-2">ورود به سیستم</h4>
</div>
<LoginComponent OnMultipleOfThree="EventCallback.Factory.Create(this, Afterlogin)" />
<div class="text-center">
<Alert Color="AlertColor.Danger" Dismissable="false">
<Icon Name="IconName.ExclamationTriangleFill" class="me-2"></Icon>@Error </Alert>
</div>
</div>
}
}
else
{
@@ -270,36 +272,17 @@
</div>
</div>
}
</div>
</div>
@code {
[Parameter] public int CompanyID { get; set; }
[Parameter] public int? ChatID { get; set; }
private ConfirmDialog dialog = default!;
private HubConnection? hubConnection;
#region fild
private bool IsEndFirstProcess { get; set; } = false;
private bool _shouldObserveVisibility = false;
int? GroupID = null;
ReadANDUpdate_CompanyDto? CompanyInfo = new();
Common.Dtos.CurrentUserInfo CurrentUser = new();
List<Read_GroupDto> CompanyGroups = new();
ChatItemDto? LastOpenChat = null;
string MsgInput = string.Empty;
IBrowserFile? SelectedImageFile = null;
byte[]? SelectedImageBytes = null;
string? SelectedImagePreview = null;
// Audio recording properties
bool IsRecording = false;
string RecordingTime = "00:00";
byte[]? RecordedAudioBytes = null;
string? RecordedAudioUrl = null;
string RecordedAudioDuration = "00:00";
private System.Threading.Timer? recordingTimer;
private DateTime recordingStartTime;
bool chatloading = false;
public bool IsLogin { get; set; } = false;
public bool IsEndFirstProcess { get; set; } = false;
string ExperYou
{
get
@@ -311,23 +294,57 @@
value += "/" + CompanyGroups.FirstOrDefault(f => f.ID == GroupID.GetValueOrDefault()).Name;
}
if (LastOpenChat != null && LastOpenChat.Responses!=null)
if (Chat != null && Chat.Responses != null)
{
var model = LastOpenChat.Responses.OrderBy(o => o.ID).LastOrDefault(l => l.Type != Common.Enums.ConversationType.UE);
var model = Chat.Responses.OrderBy(o => o.ID).LastOrDefault(l => l.Type != Common.Enums.ConversationType.UE);
if (model!=null && model.Type==Common.Enums.ConversationType.CU && !string.IsNullOrEmpty(CompanyInfo.FullNameManager))
if (model != null && model.Type == Common.Enums.ConversationType.CU && !string.IsNullOrEmpty(CompanyInfo.FullNameManager))
{
value += "/" + CompanyInfo.FullNameManager;
}
else
if (!string.IsNullOrEmpty(LastOpenChat.ExperFullName))
value += "/" + LastOpenChat.ExperFullName;
if (!string.IsNullOrEmpty(Chat.ExperFullName))
value += "/" + Chat.ExperFullName;
}
return value;
}
}
string Error = "";
#endregion
#region Image
IBrowserFile? SelectedImageFile = null;
byte[]? SelectedImageBytes = null;
string? SelectedImagePreview = null;
#endregion
#region Audio recording properties
bool IsRecording = false;
string RecordingTime = "00:00";
byte[]? RecordedAudioBytes = null;
string? RecordedAudioUrl = null;
string RecordedAudioDuration = "00:00";
private System.Threading.Timer? recordingTimer;
private DateTime recordingStartTime;
#endregion
#region Parameter
[Parameter] public int CompanyID { get; set; }
// Audio recording methods
[SupplyParameterFromQuery(Name = "ChatID")]
private int? ChatID { get; set; }
[SupplyParameterFromQuery(Name = "GroupID")]
private int? GroupID { get; set; }
#endregion
ConfirmDialog dialog = default!;
HubConnection? hubConnection;
ReadANDUpdate_CompanyDto? CompanyInfo = null;
Common.Dtos.CurrentUserInfo CurrentUser = new();
List<Read_GroupDto> CompanyGroups = new();
ChatItemDto? Chat = null;
}
@functions{
#region Audio recording methods
private async Task ToggleAudioRecording()
{
if (IsRecording)
@@ -416,271 +433,10 @@
? string.Empty
: $"data:{fileType};base64,{Convert.ToBase64String(content)}";
#endregion
}
@functions {
async Task OnClickSendMsg()
{
if (!string.IsNullOrEmpty(MsgInput) || SelectedImageFile != null || RecordedAudioBytes != null)
{
if (LastOpenChat != null)
{
Common.Enums.ConversationType type = Common.Enums.ConversationType.UE;
ChatItemResponseDto? model;
if (SelectedImageFile != null)
{
var bytes = SelectedImageBytes ?? Array.Empty<byte>();
model = await chatService.ADDChatResponse(
LastOpenChat.ID,
MsgInput,
type,
SelectedImageFile.Name,
SelectedImageFile.ContentType,
bytes);
}
else if (RecordedAudioBytes != null)
{
// Send audio message
var fileName = $"audio_{DateTimeOffset.Now.ToUnixTimeSeconds()}.wav";
model = await chatService.ADDChatResponse(
LastOpenChat.ID,
MsgInput,
type,
fileName,
"audio/wav",
RecordedAudioBytes);
}
else
{
model = await chatService.ADDChatResponse(LastOpenChat.ID, MsgInput, type);
}
LastOpenChat?.Responses.Add(model);
LastOpenChat.LastText = MsgInput;
}
else
{
//TODO New Chat
var model = await chatService.NewChatFromCurrentUser(new ADD_ConversationDto()
{
CompanyID = CompanyID,
GroupID = GroupID,
Question = MsgInput,
UserID = 0
});
if (model != null)
{
LastOpenChat = model;
}
else toastService.Notify(new ToastMessage(ToastType.Danger, "خطا در گفتگو جدید"));
}
await Task.Yield();
// Scroll to bottom for user's own messages
await JS.InvokeVoidAsync("scrollToBottom", "B1");
MsgInput = string.Empty;
SelectedImageFile = null;
SelectedImageBytes = null;
SelectedImagePreview = null;
// Clear recorded audio after sending
RecordedAudioBytes = null;
RecordedAudioUrl = null;
RecordedAudioDuration = "00:00";
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (_shouldObserveVisibility)
{
_shouldObserveVisibility = false;
await JS.InvokeVoidAsync("observeVisibility", DotNetObjectReference.Create(this));
}
}
protected override async Task OnInitializedAsync()
{
await IsOnline();
//-------------hub
var token = await localStorageService.GetItem<string>("U/key");
string AddressHub = _Http.BaseAddress.AbsoluteUri.Replace("api/", "");
hubConnection = new HubConnectionBuilder()
.WithUrl($"{AddressHub}chatNotificationHub", options =>
{
options.AccessTokenProvider = () => Task.FromResult(token);
})
.WithAutomaticReconnect()
.Build();
hubConnection.On<ChatItemResponseDto>("ReceiveNewChatItemFromCompany",async (chatitem) =>
{
if (LastOpenChat.ID == chatitem.ChatItemID)
{
LastOpenChat.Responses.Add(chatitem);
StateHasChanged();
await MarkAsRead(chatitem.ID);
// Scroll to target if exists, otherwise scroll to bottom
await JS.InvokeVoidAsync("scrollToTargetOrBottom");
}
});
//-------------------------------------
hubConnection.On<int>("CheckMarkAsRead", async (chatresponseid) =>
{
if (LastOpenChat.Responses.Any(a=>a.ID==chatresponseid && !a.IsRead && a.Type==Common.Enums.ConversationType.UE))
{
LastOpenChat.Responses.First(a => a.ID == chatresponseid).IsRead = true;
StateHasChanged();
}
});
await hubConnection.StartAsync();
//---------end hub
await base.OnInitializedAsync();
}
async Task IsOnline()
{
var token = await localStorageService.GetItem<string>("U/key");
if (string.IsNullOrEmpty(token))
{
IsLogin = false;
IsEndFirstProcess = true;
}
else
{
await baseController.RemoveToken();
await baseController.SetToken(token);
if (!await authService.IsOnline())
{
await baseController.RemoveToken();
IsLogin = false;
IsEndFirstProcess = true;
}
else
{
IsEndFirstProcess = true;
await Afterlogin();
}
}
}
async Task Afterlogin()
{
IsLogin = true;
CurrentUser = await userService.GetCurrentUserInfo();
await IsCompany();
}
async Task IsCompany()
{
CompanyInfo = await companyService.GetCompany(CompanyID);
if (CompanyInfo != null)
{ CompanyGroups = await groupService.GetGroupsCompany(CompanyID);
await IsLastChat();}
}
async Task IsLastChat()
{
if (CompanyInfo != null)
{
if (ChatID.HasValue) LastOpenChat = await ChatService.Getchat(ChatID.GetValueOrDefault());
else LastOpenChat = LastOpenChat = await ChatService.GetLastOpenChatInCompany(CompanyID);
if (LastOpenChat != null)
{
GroupID = LastOpenChat.GroupID;
// Always set up visibility observation for chat bubbles
_shouldObserveVisibility = true;
StateHasChanged();
// Wait for render to complete
await Task.Delay(200);
// Scroll to target if exists, otherwise scroll to bottom
await JS.InvokeVoidAsync("scrollToTargetOrBottom");
}
}
}
[JSInvokable]
public async Task MarkAsRead(int id)
{
if (LastOpenChat == null) return;
var msg = LastOpenChat.Responses.FirstOrDefault(m => m.ID == id);
if (msg != null && !msg.IsRead && msg.Type != Common.Enums.ConversationType.UE)
{
msg.IsRead = true;
await chatService.MarkAsReadChatItemAsync(id);
// StateHasChanged();
}
await Task.CompletedTask;
}
// Method to handle new messages from other users
public async Task HandleNewMessage()
{
if (LastOpenChat?.Responses != null)
{
var hasUnreadMessages = LastOpenChat.Responses.Any(m => !m.IsRead && m.Type != Common.Enums.ConversationType.UE);
if (hasUnreadMessages)
{
await JS.InvokeVoidAsync("autoScrollToNewMessage");
}
}
}
async Task NewChat()
{
LastOpenChat = null;
GroupID = null;
}
async Task CloseChat()
{
var options = new ConfirmDialogOptions
{
YesButtonText = "بله",
YesButtonColor = ButtonColor.Success,
NoButtonText = "انصراف",
NoButtonColor = ButtonColor.Danger
};
var confirmation = await dialog.ShowAsync(
title: "پایان دادن به گفتگو",
message1: "اطمینان دارید ؟",
confirmDialogOptions: options);
if (confirmation)
{
if (await chatService.ChatIsFinishFromUser(LastOpenChat.ID))
{
LastOpenChat.status = Common.Enums.ConversationStatus.Finished;
StateHasChanged();
}
}
}
async Task Logout()
{
await baseController.RemoveToken();
await localStorageService.RemoveItem("U/key");
IsLogin = false;
StateHasChanged();
}
async Task SelectGroup(int groupId)
{
GroupID = groupId;
StateHasChanged();
}
private string GetImageSource(byte[] bytes)
=> $"data:image/jpeg;base64,{Convert.ToBase64String(bytes)}";
private async Task HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter") await OnClickSendMsg();
}
}
@functions {
#region Image
private async Task OpenFileDialog()
{
await JS.InvokeVoidAsync("triggerClick", "chatImageInput");
@@ -701,7 +457,7 @@
await file.OpenReadStream().CopyToAsync(memoryStream);
SelectedImageBytes = memoryStream.ToArray();
SelectedImagePreview = $"data:{file.ContentType};base64,{Convert.ToBase64String(SelectedImageBytes)}";
await ClearRecordedAudio();
await ClearRecordedAudio();
}
private Task ClearSelectedImage()
@@ -727,6 +483,58 @@
}
return $"image_{DateTimeOffset.Now.ToUnixTimeSeconds()}{ext}";
}
private string GetImageSource(byte[] bytes)
=> $"data:image/jpeg;base64,{Convert.ToBase64String(bytes)}";
#endregion
}
@functions {
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (_shouldObserveVisibility)
{
_shouldObserveVisibility = false;
await JS.InvokeVoidAsync("observeVisibility", DotNetObjectReference.Create(this));
}
}
protected override async Task OnInitializedAsync()
{
Error = string.Empty;
IsEndFirstProcess = false;
if (await CheckLogin())
{
await GetCurrentUser();
if (await ExsistCompany())
{
await GetGroups();
if (ChatID.HasValue) await GetChatByID();
else if (GroupID.HasValue && !await ExsistGroup()) Error = $"گروه با شناسه {GroupID.Value} یافت برای شرکت {CompanyInfo.FullName} یافت نشد";
else await GetLastChat();
}
else Error = $"شرکت با شناسه {CompanyID} یافت نشد";
}
else await Login();
if (Chat != null)
{
GroupID = Chat.GroupID;
_shouldObserveVisibility = true;
StateHasChanged();
await Task.Delay(200);
await JS.InvokeVoidAsync("scrollToTargetOrBottom");
}
if (string.IsNullOrEmpty(Error))
{
await ConectedToHub();
}
IsEndFirstProcess = true;
await base.OnInitializedAsync();
}
public async ValueTask DisposeAsync()
{
if (hubConnection is not null)
@@ -736,6 +544,254 @@
}
}
}
@functions {
//Login
async Task<bool> CheckLogin()
{
var token = await localStorageService.GetItem<string>("U/key");
if (string.IsNullOrEmpty(token)) return false;
else
{
await baseController.RemoveToken();
await baseController.SetToken(token);
if (!await authService.IsOnline())
{
await baseController.RemoveToken();
return false;
}
else return true;
}
}
async Task Login()
{
await localStorageService.RemoveItem("CompanyID");
await localStorageService.RemoveItem("ChatID");
await localStorageService.RemoveItem("GroupID");
await localStorageService.SetItem("CompanyID", CompanyID);
if (ChatID.HasValue) await localStorageService.SetItem("ChatID", ChatID.Value);
if (GroupID.HasValue) await localStorageService.SetItem("GroupID",GroupID.Value);
NavigationManager.NavigateTo("UserPanelLogin");
}
async Task GetCurrentUser()
{
CurrentUser = await userService.GetCurrentUserInfo();
}
async Task<bool> ExsistCompany()
{
CompanyInfo = await companyService.GetCompany(CompanyID);
return CompanyInfo != null;
}
async Task GetGroups()
{
CompanyGroups = await groupService.GetGroupsCompany(CompanyID);
}
async Task<bool> ExsistGroup()
{
if (GroupID.HasValue) return (CompanyGroups.Count > 0 && CompanyGroups.Any(a => a.ID == GroupID.Value));
else return true;
}
async Task GetChatByID()
{
if (ChatID.HasValue) Chat = await ChatService.Getchat(ChatID.Value);
if (Chat == null)
{
Error = $"گفتگو با شناسه {ChatID.Value} یافت با شرکت {CompanyInfo.FullName} یافت نشد";
}
}
async Task GetLastChat()
{
Chat = await ChatService.GetLastOpenChatInCompany(CompanyID);
}
async Task OnClickSendMsg()
{
if (!string.IsNullOrEmpty(MsgInput) || SelectedImageFile != null || RecordedAudioBytes != null)
{
if (Chat != null)
{
Common.Enums.ConversationType type = Common.Enums.ConversationType.UE;
ChatItemResponseDto? model;
if (SelectedImageFile != null)
{
var bytes = SelectedImageBytes ?? Array.Empty<byte>();
model = await chatService.ADDChatResponse(
Chat.ID,
MsgInput,
type,
SelectedImageFile.Name,
SelectedImageFile.ContentType,
bytes);
}
else if (RecordedAudioBytes != null)
{
// Send audio message
var fileName = $"audio_{DateTimeOffset.Now.ToUnixTimeSeconds()}.wav";
model = await chatService.ADDChatResponse(
Chat.ID,
MsgInput,
type,
fileName,
"audio/wav",
RecordedAudioBytes);
}
else
{
model = await chatService.ADDChatResponse(Chat.ID, MsgInput, type);
}
Chat?.Responses.Add(model);
Chat.LastText = MsgInput;
}
else
{
//TODO New Chat
var model = await chatService.NewChatFromCurrentUser(new ADD_ConversationDto()
{
CompanyID = CompanyID,
GroupID = GroupID,
Question = MsgInput,
UserID = 0
});
if (model != null)
{
Chat = model;
}
else toastService.Notify(new ToastMessage(ToastType.Danger, "خطا در گفتگو جدید"));
}
await Task.Yield();
// Scroll to bottom for user's own messages
await JS.InvokeVoidAsync("scrollToBottom", "B1");
MsgInput = string.Empty;
SelectedImageFile = null;
SelectedImageBytes = null;
SelectedImagePreview = null;
// Clear recorded audio after sending
RecordedAudioBytes = null;
RecordedAudioUrl = null;
RecordedAudioDuration = "00:00";
}
}
async Task ConectedToHub()
{
//-------------hub
var token = await localStorageService.GetItem<string>("U/key");
string AddressHub = _Http.BaseAddress.AbsoluteUri.Replace("api/", "");
hubConnection = new HubConnectionBuilder()
.WithUrl($"{AddressHub}chatNotificationHub", options =>
{
options.AccessTokenProvider = () => Task.FromResult(token);
})
.WithAutomaticReconnect()
.Build();
hubConnection.On<ChatItemResponseDto>("ReceiveNewChatItemFromCompany", async (chatitem) =>
{
if (Chat.ID == chatitem.ChatItemID)
{
Chat.Responses.Add(chatitem);
StateHasChanged();
await MarkAsRead(chatitem.ID);
// Scroll to target if exists, otherwise scroll to bottom
await JS.InvokeVoidAsync("scrollToTargetOrBottom");
}
});
//-------------------------------------
hubConnection.On<int>("CheckMarkAsRead", async (chatresponseid) =>
{
if (Chat.Responses.Any(a => a.ID == chatresponseid && !a.IsRead && a.Type == Common.Enums.ConversationType.UE))
{
Chat.Responses.First(a => a.ID == chatresponseid).IsRead = true;
StateHasChanged();
}
});
await hubConnection.StartAsync();
//---------end hub
}
async Task SelectGroup(int groupId)
{
GroupID = groupId;
StateHasChanged();
}
[JSInvokable]
public async Task MarkAsRead(int id)
{
if (Chat == null) return;
var msg = Chat.Responses.FirstOrDefault(m => m.ID == id);
if (msg != null && !msg.IsRead && msg.Type != Common.Enums.ConversationType.UE)
{
msg.IsRead = true;
await chatService.MarkAsReadChatItemAsync(id);
// StateHasChanged();
}
await Task.CompletedTask;
}
// Method to handle new messages from other users
public async Task HandleNewMessage()
{
if (Chat?.Responses != null)
{
var hasUnreadMessages =Chat.Responses.Any(m => !m.IsRead && m.Type != Common.Enums.ConversationType.UE);
if (hasUnreadMessages)
{
await JS.InvokeVoidAsync("autoScrollToNewMessage");
}
}
}
async Task NewChat()
{
Chat = null;
GroupID = null;
}
async Task CloseChat()
{
var options = new ConfirmDialogOptions
{
YesButtonText = "بله",
YesButtonColor = ButtonColor.Success,
NoButtonText = "انصراف",
NoButtonColor = ButtonColor.Danger
};
var confirmation = await dialog.ShowAsync(
title: "پایان دادن به گفتگو",
message1: "اطمینان دارید ؟",
confirmDialogOptions: options);
if (confirmation)
{
if (await chatService.ChatIsFinishFromUser(Chat.ID))
{
Chat.status = Common.Enums.ConversationStatus.Finished;
StateHasChanged();
}
}
}
async Task Logout()
{
await baseController.RemoveToken();
await localStorageService.RemoveItem("U/key");
NavigationManager.NavigateTo("UserPanelLogin");
}
private async Task HandleKeyDown(KeyboardEventArgs e)
{
if (e.Key == "Enter") await OnClickSendMsg();
}
}
<style>
.chat-bubble {
padding: 0.5rem 0.75rem;