select Person and Quick-Assign expenses
This commit is contained in:
parent
033a3ebd4e
commit
8d2222de8f
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
## Optimierung Spieltag-Details
|
||||
Die Erfassung von Strafen muss möglichst schnell und komfortabel mögiich sein. Dafür muss die Seite DayDetails opimiert werden.
|
||||
Es soll möglich sein eine Person in der Teilnehmerliste auszuwählen. Bei der Erfassung einer neuen Strafe kann diese Person direkt vorbelegt werden. Außerdem soll zusätzlich zum Button "Strafe hinzufügen" ein Menü-Button angezeigt werden, der eine Kurzwahl aller Strafen mit der Option "IsOneClick" ermöglicht.
|
||||
Die Erfassung von Strafen muss möglichst schnell und komfortabel mögiich sein. Dafür muss die Seite DayDetails optimiert werden.
|
||||
Es soll möglich sein eine Person in der Teilnehmerliste auszuwählen. Bei der Erfassung einer neuen Strafe soll diese Person direkt vorbelegt werden. Außerdem soll zusätzlich zum Button "Strafe hinzufügen" ein Menü-Button angezeigt werden, der eine Kurzwahl aller Strafen mit der Option "IsOneClick" ermöglicht.
|
||||
Der Benutzer soll visuell leicht erkennen können, ob und welcher Teilnehmer aktuell markiert wurde.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -124,17 +124,28 @@
|
|||
[Parameter]
|
||||
public Guid DayId { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public Guid? PreselectedPersonId { get; set; }
|
||||
|
||||
private MudForm? _form;
|
||||
private bool _isValid;
|
||||
private ExpenseDto? _selectedExpense;
|
||||
private DayParticipantDto? _selectedParticipant;
|
||||
private decimal _customPrice;
|
||||
private bool _initialized;
|
||||
|
||||
private bool IsInverseMode => _selectedExpense?.IsInverse == true;
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
base.OnParametersSet();
|
||||
|
||||
if (!_initialized && PreselectedPersonId.HasValue)
|
||||
{
|
||||
_selectedParticipant = Participants.FirstOrDefault(p => p.PersonId == PreselectedPersonId.Value);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
if (_selectedExpense is not null)
|
||||
{
|
||||
_customPrice = _selectedExpense.Price;
|
||||
|
|
|
|||
|
|
@ -99,16 +99,27 @@ else
|
|||
}
|
||||
else
|
||||
{
|
||||
<MudList T="DayParticipantDto" Dense="true">
|
||||
<MudList T="DayParticipantDto" Dense="true" Class="participant-list">
|
||||
@foreach (var participant in Day.Participants.OrderBy(p => p.PersonName))
|
||||
{
|
||||
<MudListItem T="DayParticipantDto">
|
||||
var isSelected = _selectedParticipantId == participant.PersonId;
|
||||
<MudListItem T="DayParticipantDto"
|
||||
Class="@(isSelected ? "selected-participant" : "selectable-participant")"
|
||||
OnClick="@(() => ToggleParticipantSelection(participant.PersonId))">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Style="width: 100%">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center">
|
||||
<MudAvatar Size="Size.Small" Color="@(participant.PersonStatus == PersonStatus.Member ? Color.Primary : Color.Secondary)">
|
||||
@participant.PersonName[0]
|
||||
</MudAvatar>
|
||||
<MudText>@participant.PersonName</MudText>
|
||||
<MudBadge Visible="@isSelected"
|
||||
Color="Color.Success"
|
||||
Icon="@Icons.Material.Filled.Check"
|
||||
Overlap="true"
|
||||
Bordered="true">
|
||||
<MudAvatar Size="Size.Small"
|
||||
Color="@(isSelected ? Color.Success : (participant.PersonStatus == PersonStatus.Member ? Color.Primary : Color.Secondary))"
|
||||
Style="@(isSelected ? "border: 2px solid var(--mud-palette-success)" : "")">
|
||||
@participant.PersonName[0]
|
||||
</MudAvatar>
|
||||
</MudBadge>
|
||||
<MudText Style="@(isSelected ? "font-weight: 600" : "")">@participant.PersonName</MudText>
|
||||
@if (participant.PersonStatus == PersonStatus.Guest)
|
||||
{
|
||||
<MudChip T="string" Size="Size.Small" Variant="Variant.Outlined" Color="Color.Secondary">Gast</MudChip>
|
||||
|
|
@ -119,12 +130,21 @@ else
|
|||
<MudIconButton Icon="@Icons.Material.Filled.PersonRemove"
|
||||
Size="Size.Small"
|
||||
Color="Color.Error"
|
||||
OnClick="@(() => RemoveParticipant(participant))" />
|
||||
OnClick="@(() => RemoveParticipant(participant))"
|
||||
OnClickStopPropagation="true" />
|
||||
}
|
||||
</MudStack>
|
||||
</MudListItem>
|
||||
}
|
||||
</MudList>
|
||||
@if (_selectedParticipantId.HasValue)
|
||||
{
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Class="mt-2">
|
||||
<MudChip T="string" Color="Color.Success" Size="Size.Small" OnClose="ClearParticipantSelection">
|
||||
@SelectedParticipant?.PersonName ausgewählt
|
||||
</MudChip>
|
||||
</MudStack>
|
||||
}
|
||||
}
|
||||
</MudPaper>
|
||||
</MudItem>
|
||||
|
|
@ -204,14 +224,36 @@ else
|
|||
</MudText>
|
||||
@if (Day.Status != DayStatus.Closed)
|
||||
{
|
||||
<MudButton Variant="Variant.Text"
|
||||
Color="Color.Primary"
|
||||
StartIcon="@Icons.Material.Filled.Add"
|
||||
OnClick="OpenAddExpenseDialog"
|
||||
Size="Size.Small"
|
||||
Disabled="@(Day.Participants.Count == 0)">
|
||||
Strafe hinzufügen
|
||||
</MudButton>
|
||||
<MudStack Row="true" Spacing="1">
|
||||
@if (OneClickExpenses.Count > 0 && _selectedParticipantId.HasValue)
|
||||
{
|
||||
<MudMenu Icon="@Icons.Material.Filled.FlashOn"
|
||||
Color="Color.Warning"
|
||||
Variant="Variant.Filled"
|
||||
Size="Size.Small"
|
||||
Title="Schnellzuweisung"
|
||||
AnchorOrigin="Origin.BottomRight"
|
||||
TransformOrigin="Origin.TopRight">
|
||||
@foreach (var expense in OneClickExpenses.OrderBy(e => e.Name))
|
||||
{
|
||||
<MudMenuItem OnClick="@(() => QuickAssignExpense(expense))">
|
||||
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween" Style="min-width: 200px">
|
||||
<MudText>@expense.Name</MudText>
|
||||
<MudText Color="Color.Secondary">@expense.Price.ToString("C")</MudText>
|
||||
</MudStack>
|
||||
</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
}
|
||||
<MudButton Variant="Variant.Text"
|
||||
Color="Color.Primary"
|
||||
StartIcon="@Icons.Material.Filled.Add"
|
||||
OnClick="OpenAddExpenseDialog"
|
||||
Size="Size.Small"
|
||||
Disabled="@(Day.Participants.Count == 0)">
|
||||
Strafe hinzufügen
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
}
|
||||
</MudStack>
|
||||
|
||||
|
|
@ -331,6 +373,10 @@ else
|
|||
private DayDto? Day => DayState.Value.SelectedDay;
|
||||
private IReadOnlyList<PersonExpenseDto> Expenses => DayState.Value.SelectedDayExpenses;
|
||||
|
||||
private Guid? _selectedParticipantId;
|
||||
private DayParticipantDto? SelectedParticipant => Day?.Participants.FirstOrDefault(p => p.PersonId == _selectedParticipantId);
|
||||
private IReadOnlyList<ExpenseDto> OneClickExpenses => DayState.Value.AvailableExpenses.Where(e => e.IsOneClick && !e.IsVariable).ToList();
|
||||
|
||||
private decimal TotalExpenseAmount => Expenses.Sum(e => e.Price);
|
||||
private decimal OpenExpenseAmount => Expenses.Where(e => e.PersonExpenseStatus == PersonExpenseStatus.Open).Sum(e => e.Price);
|
||||
private decimal PaidExpenseAmount => Expenses.Where(e => e.PersonExpenseStatus == PersonExpenseStatus.Done).Sum(e => e.Price);
|
||||
|
|
@ -359,6 +405,16 @@ else
|
|||
Dispatcher.Dispatch(new ClearDayErrorAction());
|
||||
}
|
||||
|
||||
private void ToggleParticipantSelection(Guid personId)
|
||||
{
|
||||
_selectedParticipantId = _selectedParticipantId == personId ? null : personId;
|
||||
}
|
||||
|
||||
private void ClearParticipantSelection()
|
||||
{
|
||||
_selectedParticipantId = null;
|
||||
}
|
||||
|
||||
private void NavigateBack()
|
||||
{
|
||||
NavigationManager.NavigateTo("/days");
|
||||
|
|
@ -546,7 +602,8 @@ else
|
|||
{
|
||||
{ "AvailableExpenses", availableExpenses },
|
||||
{ "Participants", Day.Participants },
|
||||
{ "DayId", Day.Id }
|
||||
{ "DayId", Day.Id },
|
||||
{ "PreselectedPersonId", _selectedParticipantId }
|
||||
};
|
||||
|
||||
var dialog = await DialogService.ShowAsync<AddPersonExpenseDialog>("Strafe hinzufügen", parameters);
|
||||
|
|
@ -567,6 +624,37 @@ else
|
|||
}
|
||||
}
|
||||
|
||||
private void QuickAssignExpense(ExpenseDto expense)
|
||||
{
|
||||
if (Day is null || !_selectedParticipantId.HasValue) return;
|
||||
|
||||
if (expense.IsInverse)
|
||||
{
|
||||
var dto = new CreateInversePersonExpenseDto
|
||||
{
|
||||
ExcludedPersonId = _selectedParticipantId.Value,
|
||||
ExpenseId = expense.Id,
|
||||
DayId = Day.Id,
|
||||
GameId = null
|
||||
};
|
||||
Dispatcher.Dispatch(new CreateInversePersonExpenseAction(dto));
|
||||
Snackbar.Add($"{expense.Name} für alle außer {SelectedParticipant?.PersonName}...", Severity.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dto = new CreatePersonExpenseDto
|
||||
{
|
||||
PersonId = _selectedParticipantId.Value,
|
||||
ExpenseId = expense.Id,
|
||||
DayId = Day.Id,
|
||||
GameId = null,
|
||||
Price = null
|
||||
};
|
||||
Dispatcher.Dispatch(new CreatePersonExpenseAction(dto));
|
||||
Snackbar.Add($"{expense.Name} für {SelectedParticipant?.PersonName}...", Severity.Info);
|
||||
}
|
||||
}
|
||||
|
||||
private void MarkAsPaid(PersonExpenseDto expense)
|
||||
{
|
||||
var dto = new UpdatePersonExpenseStatusDto
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
.participant-list ::deep .mud-list-item {
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.selectable-participant {
|
||||
border-left: 3px solid transparent;
|
||||
}
|
||||
|
||||
.selectable-participant:hover {
|
||||
background-color: var(--mud-palette-action-default-hover);
|
||||
}
|
||||
|
||||
.selected-participant {
|
||||
background-color: color-mix(in srgb, var(--mud-palette-success) 15%, transparent);
|
||||
border-left: 3px solid var(--mud-palette-success);
|
||||
}
|
||||
|
||||
.selected-participant:hover {
|
||||
background-color: color-mix(in srgb, var(--mud-palette-success) 25%, transparent);
|
||||
}
|
||||
Loading…
Reference in New Issue