KoogleApp/src/Koogle.Web/Components/Pages/Expenses/Expenses.razor

194 lines
6.8 KiB
Plaintext

@page "/expenses"
@attribute [Authorize(Policy = "ClubViewer")]
@inherits Fluxor.Blazor.Web.Components.FluxorComponent
@using Fluxor
@using Koogle.Application.DTOs
@using Koogle.Domain.Enums
@using Koogle.Web.Store.ExpenseState
@using Microsoft.AspNetCore.Authorization
@inject IState<ExpenseState> ExpenseState
@inject IDispatcher Dispatcher
@inject ISnackbar Snackbar
@inject IDialogService DialogService
<PageTitle>Strafen-Vorlagen</PageTitle>
<MudText Typo="Typo.h4" Class="mb-4">Strafen-Vorlagen</MudText>
@if (ExpenseState.Value.Error is not null)
{
<MudAlert Severity="Severity.Error" Class="mb-4" ShowCloseIcon="true" CloseIconClicked="ClearError">
@ExpenseState.Value.Error
</MudAlert>
}
<MudTable Items="FilteredExpenses" Dense="true" Hover="true" Loading="ExpenseState.Value.IsLoading"
Filter="FilterFunc">
<ToolBarContent>
<MudTextField @bind-Value="_searchString"
Placeholder="Suchen..."
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
IconSize="Size.Medium"
Class="mt-0" />
<MudSpacer />
<MudSelect T="ExpenseType?" @bind-Value="_typeFilter" Label="Typ" Clearable="true" Class="mr-4" Style="width: 150px;">
<MudSelectItem Value="@((ExpenseType?)ExpenseType.Monetary)">Geldstrafe</MudSelectItem>
<MudSelectItem Value="@((ExpenseType?)ExpenseType.Material)">Sachleistung</MudSelectItem>
</MudSelect>
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add"
OnClick="OpenCreateDialog">
Neue Vorlage
</MudButton>
</ToolBarContent>
<HeaderContent>
<MudTh>Name</MudTh>
<MudTh>Preis</MudTh>
<MudTh>Typ</MudTh>
<MudTh>Optionen</MudTh>
<MudTh>Aktionen</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Name">@context.Name</MudTd>
<MudTd DataLabel="Preis">@context.Price.ToString("C")</MudTd>
<MudTd DataLabel="Typ">
<MudChip T="string" Size="Size.Small" Color="GetTypeColor(context.ExpenseType)">
@GetTypeLabel(context.ExpenseType)
</MudChip>
</MudTd>
<MudTd DataLabel="Optionen">
@if (context.IsOneClick)
{
<MudTooltip Text="One-Click: Schnellauswahl">
<MudIcon Icon="@Icons.Material.Filled.TouchApp" Size="Size.Small" Class="mr-1" />
</MudTooltip>
}
@if (context.IsInverse)
{
<MudTooltip Text="Invers: Alle außer einer Person">
<MudIcon Icon="@Icons.Material.Filled.GroupRemove" Size="Size.Small" Class="mr-1" />
</MudTooltip>
}
@if (context.IsVariable)
{
<MudTooltip Text="Variabel: Preis anpassbar">
<MudIcon Icon="@Icons.Material.Filled.Edit" Size="Size.Small" />
</MudTooltip>
}
</MudTd>
<MudTd DataLabel="Aktionen">
<MudTooltip Text="Bearbeiten">
<MudIconButton Icon="@Icons.Material.Filled.Edit"
Size="Size.Small"
OnClick="@(() => OpenEditDialog(context))"/>
</MudTooltip>
<MudTooltip Text="Löschen">
<MudIconButton Icon="@Icons.Material.Filled.Delete"
Size="Size.Small"
Color="Color.Error"
OnClick="@(() => ConfirmDelete(context))"/>
</MudTooltip>
</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager />
</PagerContent>
<NoRecordsContent>
<MudText>Keine Kosten-Vorlagen gefunden</MudText>
</NoRecordsContent>
</MudTable>
@code {
private string _searchString = "";
private ExpenseType? _typeFilter;
private IEnumerable<ExpenseDto> FilteredExpenses => _typeFilter.HasValue
? ExpenseState.Value.Expenses.Where(e => e.ExpenseType == _typeFilter.Value)
: ExpenseState.Value.Expenses;
protected override void OnInitialized()
{
base.OnInitialized();
Dispatcher.Dispatch(new LoadExpensesAction());
}
private bool FilterFunc(ExpenseDto expense)
{
if (string.IsNullOrWhiteSpace(_searchString))
return true;
return expense.Name.Contains(_searchString, StringComparison.OrdinalIgnoreCase) ||
expense.Description.Contains(_searchString, StringComparison.OrdinalIgnoreCase);
}
private void ClearError()
{
Dispatcher.Dispatch(new ClearExpenseErrorAction());
}
private static string GetTypeLabel(ExpenseType type) => type switch
{
ExpenseType.Monetary => "Geldstrafe",
ExpenseType.Material => "Sachleistung",
_ => type.ToString()
};
private static Color GetTypeColor(ExpenseType type) => type switch
{
ExpenseType.Monetary => Color.Warning,
ExpenseType.Material => Color.Info,
_ => Color.Default
};
private async Task OpenCreateDialog()
{
var dialog = await DialogService.ShowAsync<ExpenseEditDialog>("Neue Strafen-Vorlage");
var result = await dialog.Result;
if (result != null && !result.Canceled && result.Data is CreateExpenseDto dto)
{
Dispatcher.Dispatch(new CreateExpenseAction(dto));
Snackbar.Add("Vorlage wird erstellt...", Severity.Info);
}
}
private async Task OpenEditDialog(ExpenseDto expense)
{
var parameters = new DialogParameters
{
{ "Expense", expense }
};
var dialog = await DialogService.ShowAsync<ExpenseEditDialog>("Kosten-Vorlage bearbeiten", parameters);
var result = await dialog.Result;
if (result != null && !result.Canceled && result.Data is UpdateExpenseDto dto)
{
Dispatcher.Dispatch(new UpdateExpenseAction(dto));
Snackbar.Add("Vorlage wird aktualisiert...", Severity.Info);
}
}
private async Task ConfirmDelete(ExpenseDto expense)
{
var parameters = new DialogParameters
{
{ "ContentText", $"Möchten Sie \"{expense.Name}\" wirklich löschen? Diese Aktion kann nicht rückgängig gemacht werden." },
{ "ButtonText", "Löschen" },
{ "Color", Color.Error }
};
var dialog = await DialogService.ShowAsync<Koogle.Web.Components.Shared.ConfirmDialog>("Kosten-Vorlage löschen", parameters);
var result = await dialog.Result;
if (result != null && !result.Canceled)
{
Dispatcher.Dispatch(new DeleteExpenseAction(expense.Id));
Snackbar.Add("Vorlage wird gelöscht...", Severity.Info);
}
}
}