Files
Moonlight/Moonlight/Shared/Views/Support.razor
2023-06-21 19:15:30 +02:00

276 lines
13 KiB
Plaintext

@page "/support"
@using Moonlight.App.Services
@using Moonlight.App.Database.Entities
@using Moonlight.App.Helpers
@using Moonlight.App.Services.SupportChat
@using System.Text.RegularExpressions
@using Moonlight.App.Services.Files
@inject ResourceService ResourceService
@inject SupportChatClientService ClientService
@inject SmartTranslateService SmartTranslateService
@implements IDisposable
<LazyLoader Load="Load">
<div class="row">
<div class="card">
<div class="card-body">
<LazyLoader Load="LoadMessages">
<div class="scroll-y me-n5 pe-5" style="max-height: 55vh; display: flex; flex-direction: column-reverse;">
@foreach (var message in Messages.ToArray())
{
if (message.Sender == null || message.Sender.Id != User.Id)
{
<div class="d-flex justify-content-start mb-10 ">
<div class="d-flex flex-column align-items-start">
<div class="d-flex align-items-center mb-2">
<div class="symbol symbol-35px symbol-circle ">
<img alt="Logo" src="@(ResourceService.Image("logo.svg"))">
</div>
<div class="ms-3">
<a class="fs-5 fw-bold text-gray-900 text-hover-primary me-1">
@if (message.Sender != null)
{
<span>@(message.Sender.FirstName) @(message.Sender.LastName)</span>
}
else
{
<span>
<TL>System</TL>
</span>
}
</a>
<span class="text-muted fs-7 mb-1">@(Formatter.FormatAgoFromDateTime(message.CreatedAt, SmartTranslateService))</span>
</div>
</div>
<div class="p-5 rounded bg-light-info text-dark fw-semibold mw-lg-400px text-start">
@if (message.Sender == null)
{
<TL>@(message.Content)</TL>
}
else
{
int i = 0;
var arr = message.Content.Split("\n", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
foreach (var line in arr)
{
@line
if (i++ != arr.Length - 1)
{
<br />
}
}
if (message.Attachment != "")
{
<div class="mt-3">
@if (Regex.IsMatch(message.Attachment, @"\.(jpg|jpeg|png|gif|bmp)$"))
{
<img src="@(ResourceService.BucketItem("supportChat", message.Attachment))" class="img-fluid" alt="Attachment"/>
}
else
{
<a class="btn btn-secondary" href="@(ResourceService.BucketItem("supportChat", message.Attachment))">
<i class="me-2 bx bx-download"></i> @(message.Attachment)
</a>
}
</div>
}
}
</div>
</div>
</div>
}
else
{
<div class="d-flex justify-content-end mb-10 ">
<div class="d-flex flex-column align-items-end">
<div class="d-flex align-items-center mb-2">
<div class="me-3">
<span class="text-muted fs-7 mb-1">@(Formatter.FormatAgoFromDateTime(message.CreatedAt, SmartTranslateService))</span>
<a class="fs-5 fw-bold text-gray-900 text-hover-primary ms-1">
<span>@(message.Sender.FirstName) @(message.Sender.LastName)</span>
</a>
</div>
<div class="symbol symbol-35px symbol-circle ">
<img alt="Avatar" src="@(ResourceService.Avatar(message.Sender))">
</div>
</div>
<div class="p-5 rounded bg-light-primary text-dark fw-semibold mw-lg-400px text-end">
@foreach (var line in message.Content.Split("\n"))
{
@(line)<br/>
}
@if (message.Attachment != "")
{
<div class="mt-3">
@if (Regex.IsMatch(message.Attachment, @"\.(jpg|jpeg|png|gif|bmp)$"))
{
<img src="@(ResourceService.BucketItem("supportChat", message.Attachment))" class="img-fluid" alt="Attachment"/>
}
else
{
<a class="btn btn-secondary" href="@(ResourceService.BucketItem("supportChat", message.Attachment))">
<i class="me-2 bx bx-download"></i> @(message.Attachment)
</a>
}
</div>
}
</div>
</div>
</div>
}
}
<div class="d-flex justify-content-start mb-10 ">
<div class="d-flex flex-column align-items-start">
<div class="d-flex align-items-center mb-2">
<div class="symbol symbol-35px symbol-circle ">
<img alt="Logo" src="@(ResourceService.Image("logo.svg"))">
</div>
<div class="ms-3">
<a class="fs-5 fw-bold text-gray-900 text-hover-primary me-1">
<span>
<TL>System</TL>
</span>
</a>
</div>
</div>
<div class="p-5 rounded bg-light-info text-dark fw-semibold mw-lg-400px text-start">
<TL>Welcome to the support chat. Ask your question here and we will help you</TL>
</div>
</div>
</div>
</div>
</LazyLoader>
</div>
<div class="card-footer">
@if (Typing.Any())
{
<span class="mb-5 fs-5 d-flex flex-row">
<div class="wave me-1">
<div class="dot h-5px w-5px" style="margin-right: 1px;"></div>
<div class="dot h-5px w-5px" style="margin-right: 1px;"></div>
<div class="dot h-5px w-5px"></div>
</div>
@if (Typing.Length > 1)
{
<span>
@(Typing.Aggregate((current, next) => current + ", " + next)) <TL>are typing</TL>
</span>
}
else
{
<span>
@(Typing.First()) <TL>is typing</TL>
</span>
}
</span>
}
<div class="d-flex flex-stack">
<table class="w-100">
<tr>
<td class="align-top">
<SmartFileSelect @ref="SmartFileSelect"></SmartFileSelect>
</td>
<td class="w-100">
<textarea @bind="Content" @oninput="OnTyping" class="form-control mb-3 form-control-flush" rows="1" placeholder="Type a message">
</textarea>
</td>
<td class="align-top">
<WButton Text="@(SmartTranslateService.Translate("Send"))"
WorkingText="@(SmartTranslateService.Translate("Sending"))"
CssClasses="btn-primary ms-2"
OnClick="Send">
</WButton>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</LazyLoader>
@code
{
[CascadingParameter]
public User User { get; set; }
private List<SupportChatMessage> Messages = new();
private string[] Typing = Array.Empty<string>();
private string Content = "";
private DateTime LastTypingTimestamp = DateTime.UtcNow.AddMinutes(-10);
private SmartFileSelect SmartFileSelect;
private async Task Load(LazyLoader lazyLoader)
{
await lazyLoader.SetText("Starting chat client");
ClientService.OnMessage += OnMessage;
ClientService.OnTypingChanged += OnTypingChanged;
await ClientService.Start();
}
private async Task LoadMessages(LazyLoader arg)
{
Messages = (await ClientService.GetMessages()).ToList();
}
private async Task OnTypingChanged(string[] typing)
{
Typing = typing;
await InvokeAsync(StateHasChanged);
}
private async Task OnMessage(SupportChatMessage message)
{
Messages.Insert(0, message);
//TODO: Sound when message from system or admin
await InvokeAsync(StateHasChanged);
}
private async Task Send()
{
if (SmartFileSelect.SelectedFile != null && string.IsNullOrEmpty(Content))
Content = "File upload";
var message = await ClientService.SendMessage(Content, SmartFileSelect.SelectedFile);
Content = "";
await SmartFileSelect.RemoveSelection();
Messages.Insert(0, message);
await InvokeAsync(StateHasChanged);
}
private async void OnTyping()
{
if ((DateTime.UtcNow - LastTypingTimestamp).TotalSeconds > 5)
{
LastTypingTimestamp = DateTime.UtcNow;
await ClientService.SendTyping();
}
}
public void Dispose()
{
ClientService?.Dispose();
}
private void OnFileChange(InputFileChangeEventArgs obj)
{
}
}