LANCommander/LANCommander.Server/UI/Pages/Games/Index.razor
2025-08-01 02:35:23 -05:00

225 lines
7.3 KiB
Text

@page "/Games"
@using SortDirection = AntDesign.SortDirection
@using AntDesign.TableModels
@attribute [Authorize]
@inject GameService GameService
@inject NavigationManager NavigationManager
@inject ModalService ModalService
@inject IMessageService MessageService
@inject ILogger<Index> Logger
<PageHeader Title="Games" Subtitle="@Total.ToString()" />
<DataTable
@ref="Table"
TItem="Game"
@bind-SelectedRows="Selected"
@bind-Total="Total"
Size="@TableSize.Small"
Responsive
ColumnPicker
Searchable
SearchProperty="g => g.Title"
Children="(g, dg) => dg.BaseGameId == g.Id"
Query="g => g.BaseGameId == null || g.BaseGameId == Guid.Empty || (g.Type != GameType.Expansion && g.Type != GameType.Mod)">
<RightToolbar>
@if (Selected != null && Selected.Count() > 0)
{
<Button OnClick="() => AddToCollection()" Type="@ButtonType.Default">Add to Collection</Button>
}
<Button Type="@ButtonType.Default" OnClick="OpenImportDialog">Import</Button>
<Button OnClick="() => Add()" Type="@ButtonType.Primary">Add Game</Button>
</RightToolbar>
<Columns>
<Selection Key="@(context.Id.ToString())" CheckStrictly="true" />
<DataColumn TData="string" Title="Icon" Include="Media">
<Image Src="@GetIcon(context)" Height="32" Width="32" Preview="false"></Image>
</DataColumn>
<BoundDataColumn Property="g => g.Title" Sortable DefaultSortOrder="SortDirection.Ascending" />
<BoundDataColumn Property="g => g.MultiplayerModes" Include="MultiplayerModes" Sortable Title="Multiplayer">
<Checkbox Disabled="true" Checked="context.MultiplayerModes?.Count > 0" />
</BoundDataColumn>
<BoundDataColumn Property="g => g.Keys" Title="Total Keys" Include="Keys" Sortable>
@context.Keys?.Count
</BoundDataColumn>
<BoundDataColumn Property="g => g.Keys" Title="Keys Allocated" Include="Keys" Sortable>
@context.Keys?.Count(k => k.ClaimedOn.HasValue)
</BoundDataColumn>
<DataColumn TData="string[]" Title="Collections" Include="Collections">
@if (context.Collections != null)
foreach (var collection in context.Collections)
{
<Tag>@collection.Name</Tag>
}
</DataColumn>
<DataColumn TData="string[]" Title="Developers" Include="Developers" Hide>
@if (context.Developers != null)
foreach (var dev in context.Developers)
{
<Tag>@dev.Name</Tag>
}
</DataColumn>
<DataColumn TData="string[]" Title="Publishers" Include="Publishers" Hide>
@if (context.Publishers != null)
foreach (var pub in context.Publishers)
{
<Tag>@pub.Name</Tag>
}
</DataColumn>
<DataColumn TData="string[]" Title="Genres" Include="Genres" Hide>
@if (context.Genres != null)
foreach (var genre in context.Genres)
{
<Tag>@genre.Name</Tag>
}
</DataColumn>
<DataColumn TData="string[]" Title="Platforms" Include="Platforms" Hide>
@if (context.Platforms != null)
foreach (var platform in context.Platforms)
{
<Tag>@platform.Name</Tag>
}
</DataColumn>
<DataColumn TData="SDK.Enums.MultiplayerType[]" Title="Multiplayer Modes" Include="MultiplayerModes" Hide>
@if (context.MultiplayerModes != null)
foreach (var mode in context.MultiplayerModes.Select(mm => mm.Type).Distinct())
{
<Tag>@mode.GetDisplayName()</Tag>
}
</DataColumn>
<BoundDataColumn Property="g => g.CreatedOn" Title="Created On" Sortable>
<LocalTime Value="context.CreatedOn" />
</BoundDataColumn>
<BoundDataColumn Property="g => g.UpdatedOn" Title="Updated On" Sortable>
<LocalTime Value="context.UpdatedOn" />
</BoundDataColumn>
<BoundDataColumn Property="g => g.CreatedBy" Sortable Title="Created By" Include="CreatedBy">
@context.CreatedBy?.UserName
</BoundDataColumn>
<BoundDataColumn Property="g => g.UpdatedBy" Title="Updated By" Sortable Include="UpdatedBy">
@context.UpdatedBy?.UserName
</BoundDataColumn>
<DataActions TData="string">
<a href="@($"/Games/{context.Id}")" class="ant-btn ant-btn-primary">Edit</a>
<Popconfirm OnConfirm="() => Delete(context)" Title="Are you sure you want to delete this game?">
<Button Icon="@IconType.Outline.Close" Type="@ButtonType.Text" Danger />
</Popconfirm>
</DataActions>
</Columns>
<PaginationTemplate>
<Pagination
Total="context.Total"
PageSize="context.PageSize"
Current="context.PageIndex"
DefaultPageSize="25"
PageSizeOptions="new [] { 25, 50, 100, 200 }"
ShowSizeChanger
OnChange="context.HandlePageChange" />
</PaginationTemplate>
</DataTable>
@code {
bool Visibility = false;
IEnumerable<Game> Selected;
int Total;
DataTable<Game> Table;
string GetIcon(Game game)
{
var media = game?.Media?.FirstOrDefault(m => m.Type == SDK.Enums.MediaType.Icon);
if (media != null)
return $"/api/Media/{media.Id}/Download?fileId={media.FileId}";
else
return "/favicon.ico";
}
void Add()
{
NavigationManager.NavigateTo("/Games/Add");
}
async Task Delete(Game game)
{
try
{
await GameService.DeleteAsync(game);
MessageService.Success($"{game.Title} was successfully deleted!");
}
catch (Exception ex)
{
MessageService.Error("Could not delete the game!");
Logger.LogError(ex, "Could not delete the game!");
}
await Reload();
}
async void AddToCollection()
{
var modalOptions = new ModalOptions()
{
Title = "Add to Collection",
Maximizable = false,
DefaultMaximized = false,
Closable = true,
OkText = "Add"
};
var options = new AddToCollectionOptions()
{
GameIds = Selected.Select(g => g.Id)
};
var modalRef = await ModalService.CreateModalAsync<AddToCollectionDialog, AddToCollectionOptions, IEnumerable<Collection>>(modalOptions, options);
modalRef.OnOk = async (collections) =>
{
Table.UnselectAll();
await Reload();
};
}
async Task OpenImportDialog()
{
var options = new ImportDialogOptions
{
Hint = "Only LCX files are supported for importing games"
};
var modalOptions = new ModalOptions
{
Title = "Import Game",
DestroyOnClose = true,
MaskClosable = false,
Footer = null,
};
var modalRef = ModalService.CreateModal<ImportUploadDialog, ImportDialogOptions>(modalOptions, options);
modalRef.OnOk = modalRef.OnCancel = Reload;
}
async Task Reload()
{
Table.ReloadData();
}
}