fix: update migration seeding condition to check for PrimaryColor instead of TenantColor

This commit is contained in:
MarcWieland
2026-06-26 23:50:03 +02:00
parent e2e57143b8
commit f47b4d86ba
9 changed files with 1090 additions and 2 deletions
@@ -0,0 +1,230 @@
@page "/"
@rendermode InteractiveWebAssembly
@attribute [Authorize]
@inject ITimetrackerService TrackerService
@inject AuthenticationStateProvider AuthStateProvider
@inject IJSRuntime JSRuntime
<PageTitle>Dashboard Timetracker</PageTitle>
@if (_loading)
{
<MudStack AlignItems="AlignItems.Center" Class="mt-16" Spacing="3">
<MudProgressCircular Color="Color.Primary" Indeterminate="true" Size="Size.Large" />
<MudText Color="Color.Secondary">Lade Dashboard…</MudText>
</MudStack>
}
else
{
<MudStack Spacing="4">
@* ── Header & Einstellungen ── *@
<MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween">
<MudMenu Icon="@Icons.Material.Filled.Settings" AnchorOrigin="Origin.BottomRight" TransformOrigin="Origin.TopRight" Dense="true" Color="Color.Secondary">
<MudMenuItem OnClick="@(() => ToggleWidget("EarlyBird"))">
<MudCheckBox T="bool" Value="@_showEarlyBird" Label="Early Bird anzeigen" Color="Color.Primary" ReadOnly="true"/>
</MudMenuItem>
<MudMenuItem OnClick="@(() => ToggleWidget("NightOwl"))">
<MudCheckBox T="bool" Value="@_showNightOwl" Label="Night Owl anzeigen" Color="Color.Primary" ReadOnly="true"/>
</MudMenuItem>
<MudMenuItem OnClick="@(() => ToggleWidget("Pausenkonig"))">
<MudCheckBox T="bool" Value="@_showPausenkonig" Label="Pausenkönig anzeigen" Color="Color.Primary" ReadOnly="true"/>
</MudMenuItem>
<MudMenuItem OnClick="@(() => ToggleWidget("Streaks"))">
<MudCheckBox T="bool" Value="@_showStreaks" Label="Streaks anzeigen" Color="Color.Primary" ReadOnly="true"/>
</MudMenuItem>
<MudDivider />
<MudMenuItem OnClick="@(() => ToggleWidget("Charts"))">
<MudCheckBox T="bool" Value="@_showCharts" Label="Diagramme anzeigen" Color="Color.Primary" ReadOnly="true"/>
</MudMenuItem>
</MudMenu>
</MudStack>
@* ── Gamification Widgets ── *@
<MudGrid>
@if (_showEarlyBird)
{
<MudItem xs="12" sm="6" md="3">
<MudPaper Elevation="2" Class="pa-4 rounded-xl" Style="background: linear-gradient(135deg, #fdfbfb 0%, #ebedee 100%);">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
<MudAvatar Color="Color.Warning" Variant="Variant.Filled" Size="Size.Large">🌅</MudAvatar>
<MudStack Spacing="0">
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">Early Bird</MudText>
<MudText Typo="Typo.h5" Style="font-weight: 700">@FormatTimeSpan(_stats.EarliestStart)</MudText>
<MudText Typo="Typo.caption" Color="Color.Secondary">Frühester Beginn im Monat</MudText>
</MudStack>
</MudStack>
</MudPaper>
</MudItem>
}
@if (_showNightOwl)
{
<MudItem xs="12" sm="6" md="3">
<MudPaper Elevation="2" Class="pa-4 rounded-xl" Style="background: linear-gradient(135deg, #304352 0%, #d7d2cc 100%); color: white;">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
<MudAvatar Color="Color.Dark" Variant="Variant.Filled" Size="Size.Large">🦉</MudAvatar>
<MudStack Spacing="0">
<MudText Typo="Typo.subtitle2" Style="opacity: 0.8">Night Owl</MudText>
<MudText Typo="Typo.h5" Style="font-weight: 700">@FormatTimeSpan(_stats.LatestEnd)</MudText>
<MudText Typo="Typo.caption" Style="opacity: 0.8">Spätestes Ende im Monat</MudText>
</MudStack>
</MudStack>
</MudPaper>
</MudItem>
}
@if (_showPausenkonig)
{
<MudItem xs="12" sm="6" md="3">
<MudPaper Elevation="2" Class="pa-4 rounded-xl" Style="background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
<MudAvatar Color="Color.Info" Variant="Variant.Filled" Size="Size.Large">☕</MudAvatar>
<MudStack Spacing="0">
<MudText Typo="Typo.subtitle2" Color="Color.Secondary">Pausenkönig</MudText>
<MudText Typo="Typo.h5" Style="font-weight: 700">@((int)_stats.AverageBreak.TotalMinutes) Min.</MudText>
<MudText Typo="Typo.caption" Color="Color.Secondary">Ø Pause im Monat</MudText>
</MudStack>
</MudStack>
</MudPaper>
</MudItem>
}
@if (_showStreaks)
{
<MudItem xs="12" sm="6" md="3">
<MudPaper Elevation="2" Class="pa-4 rounded-xl" Style="background: linear-gradient(135deg, #f6d365 0%, #fda085 100%); color: white;">
<MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3">
<MudAvatar Color="Color.Error" Variant="Variant.Filled" Size="Size.Large">🔥</MudAvatar>
<MudStack Spacing="0">
<MudText Typo="Typo.subtitle2" Style="opacity: 0.9">Streak</MudText>
<MudText Typo="Typo.h5" Style="font-weight: 700">@_stats.CurrentStreak / @_stats.LongestStreak</MudText>
<MudText Typo="Typo.caption" Style="opacity: 0.9">Aktuell / Bester (Tage)</MudText>
</MudStack>
</MudStack>
</MudPaper>
</MudItem>
}
</MudGrid>
@* ── Diagramme ── *@
@if (_showCharts)
{
<MudGrid>
<MudItem xs="12" md="8">
<MudPaper Elevation="2" Class="pa-4 rounded-xl h-100">
<MudText Typo="Typo.h6" Class="mb-4">Gleitzeit-Verlauf @DateTime.Today.Year</MudText>
<MudChart T="double" ChartType="ChartType.Bar"
ChartSeries="@_barChartSeries"
XAxisLabels="@_barChartLabels"
Width="100%" Height="300px" />
</MudPaper>
</MudItem>
<MudItem xs="12" md="4">
<MudPaper Elevation="2" Class="pa-4 rounded-xl h-100">
<MudText Typo="Typo.h6" Class="mb-4">Jahres-Verteilung</MudText>
<MudChart T="double" ChartType="ChartType.Pie"
InputData="@_pieChartData"
InputLabels="@_pieChartLabels"
Width="100%" Height="300px" />
</MudPaper>
</MudItem>
</MudGrid>
}
</MudStack>
}
@code {
private bool _loading = true;
private DashboardStatsVm _stats = new();
private DashboardChartDataVm _chartData = new();
private bool _showEarlyBird = true;
private bool _showNightOwl = true;
private bool _showPausenkonig = true;
private bool _showStreaks = true;
private bool _showCharts = true;
private List<ChartSeries<double>> _barChartSeries = new();
private string[] _barChartLabels = Array.Empty<string>();
private double[] _pieChartData = Array.Empty<double>();
private string[] _pieChartLabels = Array.Empty<string>();
protected override async Task OnInitializedAsync()
{
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
var claim = authState.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
if (claim == null) return;
int userId = int.Parse(claim.Value);
int year = DateTime.Today.Year;
int month = DateTime.Today.Month;
await LoadSettings();
_stats = await TrackerService.GetDashboardStatsAsync(userId, year, month);
_chartData = await TrackerService.GetDashboardChartDataAsync(userId, year);
// Prepare Bar Chart
_barChartSeries = new List<ChartSeries<double>>
{
new ChartSeries<double> { Name = "Überstunden", Data = _chartData.MonthlyOvertime.Select(m => m.OvertimeHours).ToArray() }
};
_barChartLabels = _chartData.MonthlyOvertime.Select(m => m.MonthName).ToArray();
// Prepare Pie Chart
_pieChartData = new double[] { _chartData.WorkDaysCount, _chartData.VacationDaysCount, _chartData.PublicHolidaysCount };
_pieChartLabels = new string[] { "Arbeit", "Urlaub", "Feiertage" };
_loading = false;
}
private async Task LoadSettings()
{
try
{
var eb = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "widget_EarlyBird");
if (eb != null) _showEarlyBird = eb == "true";
var no = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "widget_NightOwl");
if (no != null) _showNightOwl = no == "true";
var pk = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "widget_Pausenkonig");
if (pk != null) _showPausenkonig = pk == "true";
var st = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "widget_Streaks");
if (st != null) _showStreaks = st == "true";
var ch = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "widget_Charts");
if (ch != null) _showCharts = ch == "true";
}
catch
{
// SSR Fallback
}
}
private async Task ToggleWidget(string widget)
{
bool newState = true;
if (widget == "EarlyBird") { _showEarlyBird = !_showEarlyBird; newState = _showEarlyBird; }
if (widget == "NightOwl") { _showNightOwl = !_showNightOwl; newState = _showNightOwl; }
if (widget == "Pausenkonig") { _showPausenkonig = !_showPausenkonig; newState = _showPausenkonig; }
if (widget == "Streaks") { _showStreaks = !_showStreaks; newState = _showStreaks; }
if (widget == "Charts") { _showCharts = !_showCharts; newState = _showCharts; }
try
{
await JSRuntime.InvokeVoidAsync("localStorage.setItem", $"widget_{widget}", newState.ToString().ToLower());
}
catch { }
}
private string FormatTimeSpan(TimeSpan? ts)
{
if (!ts.HasValue) return "-";
return $"{ts.Value.Hours:D2}:{ts.Value.Minutes:D2}";
}
}
@@ -1,4 +1,4 @@
@page "/"
@page "/week"
@rendermode InteractiveWebAssembly
@attribute [Authorize]
@inject ITimetrackerService TrackerService