Added tag/creator status update functionality on the API and UI layers.
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
using JSMR.Application.Circles.Queries.Search;
|
||||
using JSMR.Application.Creators.Commands.UpdateCreatorStatus;
|
||||
using JSMR.Application.Creators.Queries.Search;
|
||||
using JSMR.Application.Tags.Commands.SetEnglishName;
|
||||
using JSMR.Application.Tags.Commands.UpdateTagStatus;
|
||||
using JSMR.Application.Tags.Queries.Search;
|
||||
using JSMR.Application.Users;
|
||||
using JSMR.Application.VoiceWorks.Queries.Search;
|
||||
@@ -56,6 +59,8 @@ public static class WebApplicationExtensions
|
||||
app.MapGet("/health", () => Results.Ok(new { status = "ok" }));
|
||||
|
||||
app.MapSearchEndpoints();
|
||||
app.MapTagCommandEndpoints();
|
||||
app.MapCreatorCommandEndpoints();
|
||||
app.MapAuthenticationEndpoints();
|
||||
}
|
||||
|
||||
@@ -105,6 +110,39 @@ public static class WebApplicationExtensions
|
||||
});
|
||||
}
|
||||
|
||||
private static void MapTagCommandEndpoints(this WebApplication app)
|
||||
{
|
||||
app.MapPost("/api/tags/update-status", async (
|
||||
UpdateTagStatusRequest request,
|
||||
UpdateTagStatusHandler handler,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
var result = await handler.HandleAsync(request, ct);
|
||||
return Results.Ok(result);
|
||||
});
|
||||
|
||||
app.MapPost("/api/tags/set-english-name", async (
|
||||
SetTagEnglishNameRequest request,
|
||||
SetTagEnglishNameHandler handler,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
var result = await handler.HandleAsync(request, ct);
|
||||
return Results.Ok(result);
|
||||
});
|
||||
}
|
||||
|
||||
private static void MapCreatorCommandEndpoints(this WebApplication app)
|
||||
{
|
||||
app.MapPost("/api/creators/update-status", async (
|
||||
UpdateCreatorStatusRequest request,
|
||||
UpdateCreatorStatusHandler handler,
|
||||
CancellationToken ct) =>
|
||||
{
|
||||
var result = await handler.HandleAsync(request, ct);
|
||||
return Results.Ok(result);
|
||||
});
|
||||
}
|
||||
|
||||
private static void MapAuthenticationEndpoints(this WebApplication app)
|
||||
{
|
||||
app.MapPost("/auth/login", async (LoginRequest req, IUserRepository users, HttpContext http) =>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
public record CreatorSearchItem
|
||||
{
|
||||
public int CreatorId { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public bool Favorite { get; init; }
|
||||
public bool Blacklisted { get; init; }
|
||||
public int VoiceWorkCount { get; init; }
|
||||
public int CreatorId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
public bool Blacklisted { get; set; }
|
||||
public int VoiceWorkCount { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using JSMR.Application.Circles.Queries.Search;
|
||||
using JSMR.Application.Creators.Commands.UpdateCreatorStatus;
|
||||
using JSMR.Application.Creators.Queries.Search;
|
||||
using JSMR.Application.Scanning;
|
||||
using JSMR.Application.Tags.Commands.SetEnglishName;
|
||||
@@ -24,6 +25,7 @@ public static class ApplicationServiceCollectionExtensions
|
||||
services.AddScoped<UpdateTagStatusHandler>();
|
||||
|
||||
services.AddScoped<SearchCreatorsHandler>();
|
||||
services.AddScoped<UpdateCreatorStatusHandler>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
public record TagSearchItem
|
||||
{
|
||||
public int TagId { get; init; }
|
||||
public required string Name { get; init; }
|
||||
public bool Favorite { get; init; }
|
||||
public bool Blacklisted { get; init; }
|
||||
public string? EnglishName { get; init; }
|
||||
public int VoiceWorkCount { get; init; }
|
||||
public int TagId { get; set; }
|
||||
public required string Name { get; set; }
|
||||
public bool Favorite { get; set; }
|
||||
public bool Blacklisted { get; set; }
|
||||
public string? EnglishName { get; set; }
|
||||
public int VoiceWorkCount { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
@using JSMR.UI.Blazor.Components
|
||||
@using AntDesign
|
||||
@using JSMR.UI.Blazor.Components
|
||||
@using JSMR.UI.Blazor.Services
|
||||
|
||||
@inject SessionState Session
|
||||
@@ -6,6 +7,8 @@
|
||||
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<AntContainer />
|
||||
|
||||
<MudLayout>
|
||||
<MudAppBar Elevation="1" Dense="@_dense">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="MudBlazor.Color.Inherit" Edge="Edge.Start" OnClick="@ToggleDrawer" />
|
||||
@@ -40,6 +43,7 @@
|
||||
<MudMainContent Class="pt-18 px-8">
|
||||
@Body
|
||||
</MudMainContent>
|
||||
|
||||
@* Required *@
|
||||
<MudThemeProvider @ref="_mudThemeProvider" @bind-IsDarkMode="_isDarkMode" />
|
||||
<MudPopoverProvider />
|
||||
@@ -49,10 +53,10 @@
|
||||
|
||||
@* Needed for snackbars *@
|
||||
<MudSnackbarProvider />
|
||||
|
||||
</MudLayout>
|
||||
|
||||
<RadzenComponents @rendermode="RenderMode.InteractiveAuto" />
|
||||
<AntContainer />
|
||||
|
||||
@code{
|
||||
private bool _open = false;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
@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
|
||||
@@ -50,20 +53,29 @@
|
||||
<AntDesign.Tag Color="AntDesign.TagColor.RedInverse">Blacklisted</AntDesign.Tag>
|
||||
}
|
||||
</AntDesign.PropertyColumn>
|
||||
@* <AntDesign.ActionColumn HeaderStyle="width: 2em">
|
||||
<AntDesign.Dropdown Trigger="@(new AntDesign.Trigger[] { AntDesign.Trigger.Click })">
|
||||
<AntDesign.ActionColumn HeaderStyle="width: 5em;" Style="text-align: center">
|
||||
<Dropdown Trigger="@([Trigger.Click])">
|
||||
<Overlay>
|
||||
<AntDesign.Menu>
|
||||
<AntDesign.MenuItem>
|
||||
<span>Some Menu Item</span>
|
||||
</AntDesign.MenuItem>
|
||||
</AntDesign.Menu>
|
||||
<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>
|
||||
<AntDesign.Button Shape="AntDesign.ButtonShape.Circle" Icon="@AntDesign.IconType.Outline.More" Type="AntDesign.ButtonType.Default"></AntDesign.Button>
|
||||
<Button Icon="Ellipsis"></Button>
|
||||
</ChildContent>
|
||||
</AntDesign.Dropdown>
|
||||
</AntDesign.ActionColumn> *@
|
||||
</Dropdown>
|
||||
</AntDesign.ActionColumn>
|
||||
</ColumnDefinitions>
|
||||
</AntDesign.Table>
|
||||
<JPagination2 PageNumber="PageNumber" PageNumberChanged="OnPageNumberChanged" PageSize="PageSize" PageSizeChanged="OnPageSizeChanged" TotalItems="TotalItems" />
|
||||
@@ -119,6 +131,9 @@
|
||||
[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;
|
||||
@@ -259,4 +274,31 @@
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
@inject IJSRuntime JS
|
||||
@using AntDesign
|
||||
@using JSMR.Application.Common.Search
|
||||
@using JSMR.Application.Tags.Commands.UpdateTagStatus
|
||||
@using JSMR.Application.Tags.Contracts
|
||||
@using JSMR.Application.Tags.Queries.Search
|
||||
@using JSMR.Application.Tags.Queries.Search.Contracts
|
||||
@using JSMR.UI.Blazor.Components
|
||||
@@ -13,10 +15,6 @@
|
||||
<PageTitle>Tags</PageTitle>
|
||||
|
||||
<div class="fdsfds">
|
||||
@* <h1>Tags</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=@("Tags") Class="ant-blurred-card">
|
||||
<Extra>
|
||||
<AntDesign.Input TValue="string" Value="Keywords" ValueChanged="OnKeywordsChanged" DebounceMilliseconds="500" Placeholder="Filter">
|
||||
@@ -53,14 +51,34 @@
|
||||
<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, TagStatus.Favorite)">Set as Favorite</MenuItem>
|
||||
}
|
||||
@if (!context.Blacklisted)
|
||||
{
|
||||
<MenuItem OnClick="(e) => SetStatus(context, TagStatus.Blacklisted)">Set as Blacklisted</MenuItem>
|
||||
}
|
||||
@if (context.Favorite || context.Blacklisted)
|
||||
{
|
||||
<MenuItem OnClick="(e) => SetStatus(context, TagStatus.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>
|
||||
|
||||
@* <Pagination Current="PageNumber" OnChange="OnPaginationChange" PageSize="PageSize" Total="TotalItems" ShowTotal="ShowTotal"></Pagination>
|
||||
<JPagination PageNumber="PageNumber" PageNumberChanged="OnPageNumberChanged" PageSize="PageSize" PageSizeChanged="OnPageSizeChanged" TotalItems="TotalItems" /> *@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@@ -124,6 +142,9 @@
|
||||
[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;
|
||||
@@ -280,4 +301,31 @@
|
||||
|
||||
NavigationManager.NavigateTo(uri);
|
||||
}
|
||||
|
||||
private async Task SetStatus(TagSearchItem item, TagStatus status)
|
||||
{
|
||||
UpdateTagStatusRequest request = new(
|
||||
TagId: item.TagId,
|
||||
TagStatus: status
|
||||
);
|
||||
|
||||
UpdateTagStatusResponse? response = await Client.UpdateTagStatusAsync(request);
|
||||
|
||||
if (response is not null)
|
||||
{
|
||||
item.Favorite = response.TagStatus is TagStatus.Favorite;
|
||||
item.Blacklisted = response.TagStatus is TagStatus.Blacklisted;
|
||||
}
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
var config = new NotificationConfig()
|
||||
{
|
||||
Message = $"Tag Status Update",
|
||||
Description = $"Tag '{item.Name}' set to {status.ToString()}.",
|
||||
Placement = NotificationPlacement.Top
|
||||
};
|
||||
|
||||
await NotificationService.Open(config);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using JSMR.Application.Circles.Queries.Search;
|
||||
using JSMR.Application.Creators.Commands.UpdateCreatorStatus;
|
||||
using JSMR.Application.Creators.Queries.Search;
|
||||
using JSMR.Application.Tags.Commands.UpdateTagStatus;
|
||||
using JSMR.Application.Tags.Queries.Search;
|
||||
using JSMR.Application.VoiceWorks.Queries.Search;
|
||||
using System.Net.Http.Json;
|
||||
@@ -41,4 +43,16 @@ public class VoiceWorksClient(HttpClient http)
|
||||
using var resp = await http.PostAsJsonAsync("/api/tags/search", request, ct);
|
||||
return await resp.Content.ReadFromJsonAsync<SearchTagsResponse>(JsonOptions, cancellationToken: ct);
|
||||
}
|
||||
|
||||
public async Task<UpdateTagStatusResponse?> UpdateTagStatusAsync(UpdateTagStatusRequest request, CancellationToken ct = default)
|
||||
{
|
||||
using var resp = await http.PostAsJsonAsync("/api/tags/update-status", request, ct);
|
||||
return await resp.Content.ReadFromJsonAsync<UpdateTagStatusResponse>(JsonOptions, cancellationToken: ct);
|
||||
}
|
||||
|
||||
public async Task<UpdateCreatorStatusResponse?> UpdateCreatorStatusAsync(UpdateCreatorStatusRequest request, CancellationToken ct = default)
|
||||
{
|
||||
using var resp = await http.PostAsJsonAsync("/api/creators/update-status", request, ct);
|
||||
return await resp.Content.ReadFromJsonAsync<UpdateCreatorStatusResponse>(JsonOptions, cancellationToken: ct);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user