Files
jsmr/JSMR.UI.Blazor/Components/JProduct.razor
Brian Bicknell 9c9e33ebec
All checks were successful
ci / build-test (push) Successful in 2m44s
ci / publish-image (push) Successful in 1m45s
Added initial voice work edit logic (set favorite / delete) on Api and UI layers.
2026-05-07 00:07:20 -04:00

249 lines
10 KiB
Plaintext

@using AntDesign
@using JSMR.Application.VoiceWorks.Commands.SetFavorite
@using JSMR.Application.VoiceWorks.Queries.Search
@using JSMR.Domain.Enums
@using JSMR.UI.Blazor.Components.Chips
@using JSMR.UI.Blazor.Enums
@using JSMR.UI.Blazor.Filters
@using JSMR.UI.Blazor.Services
@using System.Globalization
@using Microsoft.AspNetCore.WebUtilities
@inject VoiceWorksClient Client
@inject MessageService MessageService
@inject ModalService ModalService
<div class=@GetCardClasses(Product)>
<div class="j-voice-work-image-container">
<JImage OverlayClass="j-voice-work-image-overlay" ImageClass="j-voice-work-image" Source="@ImageUrlProvider.GetImageUrl(Product, "main")" FallbackSource="@ImageUrlProvider.GetImageUrl(Product, "main", "webp")"></JImage>
</div>
<div class="j-voice-work-content">
<div class="j-product-title">
<a href="@Product.ProductUrl" target="_blank">@Product.ProductName</a>
</div>
<BitStack Horizontal="true" Gap="0.5em" AutoHeight Wrap>
<Chip Graphic="Graphic.Circle" Varient="ElementVarient.Outlined" Color="ColorVarient.Secondary" Url=@($"https://www.dlsite.com/maniax/circle/profile/=/maker_id/{Product.MakerId}.html")>@Product.Maker</Chip>
@if (Product.OriginalCircle is not null)
{
<Chip Graphic="Graphic.Circle" Varient="ElementVarient.Outlined" Color="ColorVarient.Secondary" Url=@($"https://www.dlsite.com/maniax/circle/profile/=/maker_id/{Product.OriginalCircle.MakerId}.html")>@Product.OriginalCircle.Name</Chip>
}
@foreach (var creator in Product.Creators)
{
<Chip Graphic="Graphic.Person" Varient="ElementVarient.Outlined" IconVarient="IconVarient.Fill" Color="ColorVarient.Secondary" Url=@($"https://www.dlsite.com/maniax/fsr/=/keyword_creater/{creator.Name}")>@creator.Name</Chip>
}
</BitStack>
<BitStack Horizontal="true" Gap="0.5em" AutoHeight Wrap>
@foreach (string supportedLanguage in Product.SupportedLanguages)
{
<Chip Graphic="Graphic.Globe" Varient="ElementVarient.Outlined" Color="ColorVarient.Secondary">@GetSupportedLanguageDescription(supportedLanguage)</Chip>
}
@if (Product.OriginalProductId is not null)
{
<Chip Graphic="Graphic.Translate" Varient="ElementVarient.Outlined" Color="ColorVarient.Secondary">Translation</Chip>
}
@if (Product.Rating == AgeRating.AllAges)
{
<Chip Graphic="Graphic.Age" Color="ColorVarient.Green" Varient="ElementVarient.Outlined">All Ages</Chip>
}
else if (Product.Rating == AgeRating.R15)
{
<Chip Graphic="Graphic.Age" Color="ColorVarient.Blue" Varient="ElementVarient.Outlined">R-15</Chip>
}
@if (Product.HasTrial || Product.HasChobit)
{
<Chip Graphic="Graphic.Download" Color="ColorVarient.Yellow" Varient="ElementVarient.Outlined">Trial</Chip>
}
@if (Product.Favorite)
{
<Chip Graphic="Graphic.Star" Color="ColorVarient.Teal" Varient="ElementVarient.Outlined">Favorite</Chip>
}
</BitStack>
<div class="j-product-description">@Product.Description</div>
<div class="j-tags">
@foreach (var tag in Product.Tags)
{
<ProductTag Tag="tag"></ProductTag>
}
</div>
</div>
<div class="j-voice-work-info">
<div class="j-release-date-container">
<span class="j-icon j-icon-calendar"></span>
<span>@GetReleaseDateText(Product)</span>
</div>
<div class="j-wishlist-container">
<span class="j-icon j-icon-star j-icon-color-yellow"></span>
<span>@((Product.WishlistCount ?? 0).ToString("n0"))</span>
</div>
@if (Product.SalesDate is not null)
{
<div class="j-downloads-container">
<span class="j-icon j-icon-bag-fill j-icon-color-green"></span>
<span>@((Product.Downloads ?? 0).ToString("n0"))</span>
</div>
}
@* <div class="j-icon-2 j-icon-2-flag-@GetFlagClassSuffix(Product)"></div> *@
<div class="j-spacer"></div>
<BitStack Horizontal="true" Gap="0.5rem" VerticalAlign="BitAlignment.End" HorizontalAlign="BitAlignment.End">
@if (Product.IsValid != true)
{
@* <ProductIndicator Graphic="Graphic.Warning" IconVarient="IconVarient.Fill" Color="ColorVarient.Orange" BackgroundColor="ColorVarient.Black"></ProductIndicator> *@
<Chip Graphic="Graphic.Warning" IconVarient="IconVarient.Fill" Varient="ElementVarient.Outlined" Color="ColorVarient.Orange" ThickBorder></Chip>
}
@if (Product.OriginalProductId is not null)
{
@* <ProductIndicator Graphic="Graphic.Translate" Color="ColorVarient.Primary" BackgroundColor="ColorVarient.Black"></ProductIndicator> *@
<Chip Graphic="Graphic.Translate" Varient="ElementVarient.Outlined" Color="ColorVarient.Primary" ThickBorder></Chip>
}
@if (Product.Favorite)
{
@* <ProductIndicator Graphic="Graphic.Star" Color="ColorVarient.Pink" BackgroundColor="ColorVarient.Black"></ProductIndicator> *@
<Chip Graphic="Graphic.Star" Varient="ElementVarient.Outlined" Color="ColorVarient.Pink" ThickBorder></Chip>
}
@if (Product.HasTrial || Product.HasChobit)
{
@* <ProductIndicator Graphic="Graphic.Headphones" Color="ColorVarient.Blue" BackgroundColor="ColorVarient.Black"></ProductIndicator> *@
<Chip Graphic="Graphic.Headphones" Varient="ElementVarient.Outlined" Color="ColorVarient.Blue" ThickBorder></Chip>
}
<Dropdown Trigger="@([Trigger.Click])">
<Overlay>
<Menu Selectable="false">
@if (!Product.Favorite)
{
<MenuItem OnClick="(e) => SetFavorite(true)">Add to Favorites</MenuItem>
}
@if (Product.Favorite)
{
<MenuItem OnClick="(e) => SetFavorite(false)">Remove from Favorites</MenuItem>
}
@if (Product.IsValid != true)
{
<MenuItem OnClick="(e) => Delete()">Delete</MenuItem>
}
</Menu>
</Overlay>
<ChildContent>
<Chip Graphic="Graphic.Pencil" Varient="ElementVarient.Outlined" Color="ColorVarient.Surface" IsClickable ThickBorder></Chip>
</ChildContent>
</Dropdown>
</BitStack>
</div>
</div>
@code {
[Parameter]
public required VoiceWorkSearchResult Product { get; set; }
private string GetCardClasses(VoiceWorkSearchResult voiceWork)
{
List<string> classNames = ["j-card", "j-voice-work-card"];
if (voiceWork.Status == (byte)VoiceWorkStatus.NewRelease)
{
classNames.Add("type-sale");
}
else if (voiceWork.Status == (byte)VoiceWorkStatus.NewAndUpcoming)
{
classNames.Add("type-new");
}
return string.Join(" ", classNames);
}
private string GetReleaseDateText(VoiceWorkSearchResult voiceWork)
{
if (voiceWork.SalesDate.HasValue)
{
return voiceWork.SalesDate.Value.ToString("MMMM d, yyyy", CultureInfo.CurrentCulture);
}
if (voiceWork.PlannedReleaseDate.HasValue)
{
return voiceWork.PlannedReleaseDate.Value.ToString("MMMM d, yyyy", CultureInfo.CurrentCulture);
}
if (voiceWork.ExpectedDate.HasValue)
{
string part = voiceWork.ExpectedDate.Value.Day switch
{
21 => "Late",
11 => "Middle",
_ => "Early"
};
return $"{part} {voiceWork.ExpectedDate.Value.ToString("MMMM yyyy")}";
}
return "Unknown";
}
private string GetFlagClassSuffix(VoiceWorkSearchResult voiceWork)
{
switch (voiceWork.SubtitleLanguage)
{
case 1:
return "us";
case 2:
return "cn";
case 3:
return "kr";
default:
return "jp";
}
}
private string GetSupportedLanguageDescription(string code)
{
switch (code)
{
case "JPN": return "Japanese";
case "ENG": return "English";
case "CHI_HANS": return "Chinese (Simplified)";
case "CHI_HANT": return "Chinese (Traditional)";
case "KO_KR": return "Korean";
default: return code;
}
}
private async Task SetFavorite(bool value)
{
SetVoiceWorkFavoriteRequest request = new(
VoiceWorkId: Product.VoiceWorkId,
IsFavorite: value
);
SetVoiceWorkFavoriteResponse? response = await Client.SetVoiceWorkFavoriteeAsync(request);
if (response is not null)
{
Product.Favorite = response.IsFavorite;
}
//await InvokeAsync(StateHasChanged);
MessageConfig messageConfig = new()
{
Content = $"Product '{Product.ProductName}' has been {(Product.Favorite ? "added to your favorites" : "removed from your favorites")}.",
Type = MessageType.Success
};
_ = MessageService.OpenAsync(messageConfig);
}
private async Task Delete()
{
RenderFragment icon = @<AntDesign.Icon Type="@IconType.Outline.ExclamationCircle" />;
AntDesign.ConfirmOptions options = new()
{
Title = "Are you sure you want to delete the following product?",
Icon = icon,
Content = Product.ProductName
};
await ModalService.ConfirmAsync(options);
}
}