304 lines
11 KiB
Plaintext
304 lines
11 KiB
Plaintext
@page "/creators"
|
|
@inject VoiceWorksClient Client
|
|
@inject IJSRuntime JS
|
|
@using AntDesign
|
|
@using JSMR.Application.Common.Search
|
|
@using JSMR.Application.Creators.Commands.UpdateCreatorStatus
|
|
@using JSMR.Application.Creators.Contracts
|
|
@using JSMR.Application.Creators.Queries.Search
|
|
@using JSMR.Application.Creators.Queries.Search.Contracts
|
|
@using JSMR.UI.Blazor.Components
|
|
@using JSMR.UI.Blazor.Filters
|
|
@using JSMR.UI.Blazor.Services
|
|
@using Microsoft.AspNetCore.WebUtilities
|
|
|
|
<PageTitle>Creators</PageTitle>
|
|
|
|
@* <h1>Creators</h1>
|
|
|
|
<MudTextField T="string" Value="Keywords" ValueChanged="OnKeywordsChanged" Immediate="true" DebounceInterval="500" Label="Filter" Variant="MudBlazor.Variant.Text" Adornment="@Adornment.Start" AdornmentIcon="@Icons.Material.Outlined.Search" />
|
|
*@
|
|
|
|
<AntDesign.Card Title=@("Creators") Class="ant-blurred-card">
|
|
<Extra>
|
|
<AntDesign.Input TValue="string" Value="Keywords" ValueChanged="OnKeywordsChanged" DebounceMilliseconds="500" Placeholder="Filter">
|
|
<Prefix>
|
|
<AntDesign.Icon Type="@AntDesign.IconType.Outline.Search" />
|
|
</Prefix>
|
|
</AntDesign.Input>
|
|
</Extra>
|
|
<Body>
|
|
<AntDesign.Table DataSource="@(searchResults?.Items ?? Enumerable.Empty<CreatorSearchItem>())"
|
|
Total="@(searchResults?.TotalItems ?? 0)"
|
|
TItem="CreatorSearchItem"
|
|
Loading="LoadingData"
|
|
HidePagination="@true"
|
|
RemoteDataSource="@true"
|
|
RowKey="x=>x.CreatorId"
|
|
OnChange="HandleTableChange">
|
|
<ColumnDefinitions>
|
|
<AntDesign.PropertyColumn Property="c => c.Name" Title="Name" Sortable="true" SorterMultiple="4" />
|
|
<AntDesign.PropertyColumn Property="c => c.VoiceWorkCount" Title="Voice Works" Format="n0" HeaderStyle="width: 10em" Sortable="true" SorterMultiple="4">
|
|
<AntDesign.Button Size="AntDesign.ButtonSize.Small" Type="AntDesign.ButtonType.Link" OnClick="@(e => NavigateToVoiceWorkSearch(context))" Style="display:flex;justify-self:flex-end;">@context.VoiceWorkCount.ToString("n0")</AntDesign.Button>
|
|
</AntDesign.PropertyColumn>
|
|
<AntDesign.PropertyColumn Property="c => c.Favorite" Title="Favorite" HeaderStyle="width: 8em" Sortable="true" SortDirections="new[] { AntDesign.SortDirection.Descending }" SorterMultiple="4">
|
|
@if (context.Favorite)
|
|
{
|
|
<AntDesign.Tag Color="AntDesign.TagColor.PurpleInverse">Favorite</AntDesign.Tag>
|
|
}
|
|
</AntDesign.PropertyColumn>
|
|
<AntDesign.PropertyColumn Property="c => c.Blacklisted" Title="Blacklisted" HeaderStyle="width: 9em" Sortable="true" SortDirections="new[] { AntDesign.SortDirection.Descending }" SorterMultiple="4">
|
|
@if (context.Blacklisted)
|
|
{
|
|
<AntDesign.Tag Color="AntDesign.TagColor.RedInverse">Blacklisted</AntDesign.Tag>
|
|
}
|
|
</AntDesign.PropertyColumn>
|
|
<AntDesign.ActionColumn HeaderStyle="width: 5em;" Style="text-align: center">
|
|
<Dropdown Trigger="@([Trigger.Click])">
|
|
<Overlay>
|
|
<Menu Selectable="false">
|
|
@if (!context.Favorite)
|
|
{
|
|
<MenuItem OnClick="(e) => SetStatus(context, CreatorStatus.Favorite)">Set as Favorite</MenuItem>
|
|
}
|
|
@if (!context.Blacklisted)
|
|
{
|
|
<MenuItem OnClick="(e) => SetStatus(context, CreatorStatus.Blacklisted)">Set as Blacklisted</MenuItem>
|
|
}
|
|
@if (context.Favorite || context.Blacklisted)
|
|
{
|
|
<MenuItem OnClick="(e) => SetStatus(context, CreatorStatus.Neutral)">Set as Neutral</MenuItem>
|
|
}
|
|
</Menu>
|
|
</Overlay>
|
|
<ChildContent>
|
|
<Button Icon="Ellipsis"></Button>
|
|
</ChildContent>
|
|
</Dropdown>
|
|
</AntDesign.ActionColumn>
|
|
</ColumnDefinitions>
|
|
</AntDesign.Table>
|
|
<JPagination2 PageNumber="PageNumber" PageNumberChanged="OnPageNumberChanged" PageSize="PageSize" PageSizeChanged="OnPageSizeChanged" TotalItems="TotalItems" />
|
|
</Body>
|
|
</AntDesign.Card>
|
|
|
|
<style>
|
|
.mud-table-root {
|
|
table-layout: fixed;
|
|
}
|
|
|
|
body {
|
|
background-image: url(https://mdn.alipayobjects.com/huamei_iwk9zp/afts/img/A*ETkNSJ-oUGwAAAAAQ_AAAAgAegCCAQ/original);
|
|
background-size: cover;
|
|
}
|
|
|
|
.ant-blurred-card {
|
|
background-color: color-mix(in srgb, #141414 70%, transparent);
|
|
-webkit-backdrop-filter: blur(12px);
|
|
backdrop-filter: blur(12px);
|
|
}
|
|
|
|
.ant-card-extra {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
width: 50%;
|
|
}
|
|
|
|
.ant-table {
|
|
/* background: inherit; */
|
|
}
|
|
|
|
.ant-table table {
|
|
table-layout: fixed;
|
|
}
|
|
|
|
.j-pager {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
justify-content: center;
|
|
z-index: 2;
|
|
background: var(--mud-palette-background);
|
|
padding: .5em 1em;
|
|
}
|
|
</style>
|
|
|
|
@code {
|
|
[Inject]
|
|
protected NavigationManager NavigationManager { get; set; } = default!;
|
|
|
|
[Inject]
|
|
INotificationService NotificationService { get; set; } = default!;
|
|
|
|
public string? Keywords { get; set; }
|
|
public int PageNumber { get; set; } = 1;
|
|
public int PageSize { get; set; } = 100;
|
|
public int TotalItems => searchResults?.TotalItems ?? 0;
|
|
|
|
public bool LoadingData { get; set; }
|
|
|
|
SearchResult<CreatorSearchItem>? searchResults;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
//await UpdateDataAsync(true);
|
|
}
|
|
|
|
public async Task OnKeywordsChanged(string? newKeywords)
|
|
{
|
|
Keywords = newKeywords;
|
|
await UpdateDataAsync(true);
|
|
}
|
|
|
|
public async Task OnPageNumberChanged(int newPageNumber)
|
|
{
|
|
PageNumber = newPageNumber;
|
|
await UpdateDataAsync(false);
|
|
}
|
|
|
|
public async Task OnPageSizeChanged(int newPageSize)
|
|
{
|
|
PageSize = newPageSize;
|
|
await UpdateDataAsync(true);
|
|
}
|
|
|
|
private async Task UpdateDataAsync(bool resetPageNumber)
|
|
{
|
|
if (resetPageNumber)
|
|
PageNumber = 1;
|
|
|
|
await LoadCreatorsAsync();
|
|
}
|
|
|
|
private async Task LoadCreatorsAsync()
|
|
{
|
|
LoadingData = true;
|
|
|
|
SearchCreatorsRequest request = new(
|
|
Options: new()
|
|
{
|
|
PageNumber = PageNumber,
|
|
PageSize = PageSize,
|
|
Criteria = new()
|
|
{
|
|
Name = Keywords
|
|
},
|
|
SortOptions = [.. _sortOptions]
|
|
}
|
|
);
|
|
|
|
await JS.InvokeVoidAsync("pageHelpers.scrollToTop");
|
|
var result = await Client.SearchAsync(request);
|
|
|
|
searchResults = result?.Results ?? new();
|
|
|
|
LoadingData = false;
|
|
|
|
//await InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
private List<SortOption<CreatorSortField>> _sortOptions =
|
|
[
|
|
new(CreatorSortField.Name, Application.Common.Search.SortDirection.Ascending)
|
|
];
|
|
|
|
private async Task HandleTableChange(AntDesign.TableModels.QueryModel<CreatorSearchItem> queryModel)
|
|
{
|
|
//PageNumber = queryModel.PageIndex;
|
|
//PageSize = queryModel.PageSize;
|
|
|
|
_sortOptions = MapSortOptions(queryModel);
|
|
|
|
await LoadCreatorsAsync();
|
|
}
|
|
|
|
private List<SortOption<CreatorSortField>> MapSortOptions(AntDesign.TableModels.QueryModel<CreatorSearchItem> queryModel)
|
|
{
|
|
var requestedSorts = queryModel.SortModel
|
|
.Select(sort => new
|
|
{
|
|
Field = sort.FieldName switch
|
|
{
|
|
nameof(CreatorSearchItem.Favorite) => CreatorSortField.Favorite,
|
|
nameof(CreatorSearchItem.Blacklisted) => CreatorSortField.Blacklisted,
|
|
nameof(CreatorSearchItem.VoiceWorkCount) => CreatorSortField.VoiceWorkCount,
|
|
nameof(CreatorSearchItem.Name) => CreatorSortField.Name,
|
|
_ => (CreatorSortField?)null
|
|
},
|
|
Direction = sort.SortDirection switch
|
|
{
|
|
AntDesign.SortDirection.Ascending => Application.Common.Search.SortDirection.Ascending,
|
|
AntDesign.SortDirection.Descending => Application.Common.Search.SortDirection.Descending,
|
|
_ => (Application.Common.Search.SortDirection?)null
|
|
}
|
|
})
|
|
.Where(x => x.Field is not null && x.Direction is not null)
|
|
.ToDictionary(x => x.Field!.Value, x => x.Direction!.Value);
|
|
|
|
var finalSorts = new List<SortOption<CreatorSortField>>();
|
|
|
|
// Force your preferred precedence
|
|
if (requestedSorts.TryGetValue(CreatorSortField.Favorite, out var favoriteDir))
|
|
finalSorts.Add(new(CreatorSortField.Favorite, favoriteDir));
|
|
|
|
if (requestedSorts.TryGetValue(CreatorSortField.Blacklisted, out var blacklistedDir))
|
|
finalSorts.Add(new(CreatorSortField.Blacklisted, blacklistedDir));
|
|
|
|
if (requestedSorts.TryGetValue(CreatorSortField.VoiceWorkCount, out var countDir))
|
|
finalSorts.Add(new(CreatorSortField.VoiceWorkCount, countDir));
|
|
|
|
if (requestedSorts.TryGetValue(CreatorSortField.Name, out var nameDir))
|
|
finalSorts.Add(new(CreatorSortField.Name, nameDir));
|
|
|
|
// Default fallback
|
|
if (finalSorts.Count == 0)
|
|
finalSorts.Add(new(CreatorSortField.Name, Application.Common.Search.SortDirection.Ascending));
|
|
|
|
return finalSorts;
|
|
}
|
|
|
|
private void NavigateToVoiceWorkSearch(CreatorSearchItem item)
|
|
{
|
|
VoiceWorkFilterState state = new()
|
|
{
|
|
CreatorIds = [item.CreatorId]
|
|
};
|
|
|
|
//string basePath = new Uri(NavigationManager.Uri).GetLeftPart(UriPartial.Path);
|
|
string basePath = new Uri(NavigationManager.Uri).GetLeftPart(UriPartial.Authority);
|
|
string uri = QueryHelpers.AddQueryString($"{basePath}/voiceworks", state.ToQuery());
|
|
|
|
NavigationManager.NavigateTo(uri);
|
|
}
|
|
|
|
private async Task SetStatus(CreatorSearchItem item, CreatorStatus status)
|
|
{
|
|
UpdateCreatorStatusRequest request = new(
|
|
CreatorId: item.CreatorId,
|
|
CreatorStatus: status
|
|
);
|
|
|
|
UpdateCreatorStatusResponse? response = await Client.UpdateCreatorStatusAsync(request);
|
|
|
|
if (response is not null)
|
|
{
|
|
item.Favorite = response.CreatorStatus is CreatorStatus.Favorite;
|
|
item.Blacklisted = response.CreatorStatus is CreatorStatus.Blacklisted;
|
|
}
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
|
|
var config = new NotificationConfig()
|
|
{
|
|
Message = $"Creator Status Update",
|
|
Description = $"Creator '{item.Name}' set to {status.ToString()}.",
|
|
Placement = NotificationPlacement.Top
|
|
};
|
|
|
|
await NotificationService.Open(config);
|
|
}
|
|
} |