Loading angepasst
This commit is contained in:
@@ -48,6 +48,9 @@
|
|||||||
</MudLayout>
|
</MudLayout>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public TenantInfo? PersistentTenantInfo { get; set; }
|
||||||
|
|
||||||
private bool _drawerOpen = true;
|
private bool _drawerOpen = true;
|
||||||
private bool _isDarkMode;
|
private bool _isDarkMode;
|
||||||
|
|
||||||
@@ -55,10 +58,31 @@
|
|||||||
{
|
{
|
||||||
UserNotificationService.OnUserDeleted += HandleUserDeleted;
|
UserNotificationService.OnUserDeleted += HandleUserDeleted;
|
||||||
|
|
||||||
|
if (PersistentTenantInfo != null)
|
||||||
|
{
|
||||||
|
ApplyTheme(PersistentTenantInfo);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var tenantInfo = await Http.GetFromJsonAsync<TenantInfo>("api/tenant/current");
|
var tenantInfo = await Http.GetFromJsonAsync<TenantInfo>("api/tenant/current");
|
||||||
if (tenantInfo?.IsTenant == true && !string.IsNullOrEmpty(tenantInfo.PrimaryColor))
|
if (tenantInfo != null)
|
||||||
|
{
|
||||||
|
ApplyTheme(tenantInfo);
|
||||||
|
PersistentTenantInfo = tenantInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore background error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyTheme(TenantInfo tenantInfo)
|
||||||
|
{
|
||||||
|
if (tenantInfo.IsTenant && !string.IsNullOrEmpty(tenantInfo.PrimaryColor))
|
||||||
{
|
{
|
||||||
var primaryColor = tenantInfo.PrimaryColor;
|
var primaryColor = tenantInfo.PrimaryColor;
|
||||||
var secondaryColor = tenantInfo.SecondaryColor ?? tenantInfo.PrimaryColor;
|
var secondaryColor = tenantInfo.SecondaryColor ?? tenantInfo.PrimaryColor;
|
||||||
@@ -90,11 +114,6 @@
|
|||||||
_theme.PaletteDark.PrimaryContrastText = textCol;
|
_theme.PaletteDark.PrimaryContrastText = textCol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignore background error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool IsLightColor(string hexColor)
|
private bool IsLightColor(string hexColor)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -96,12 +96,21 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentCompanyName { get; set; }
|
||||||
|
|
||||||
[Parameter] public EventCallback OnToggleDrawer { get; set; }
|
[Parameter] public EventCallback OnToggleDrawer { get; set; }
|
||||||
|
|
||||||
private bool _showVersionBadge;
|
private bool _showVersionBadge;
|
||||||
private string _companyName = "Hauptdomain";
|
private string _companyName = "Hauptdomain";
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (PersistentCompanyName != null)
|
||||||
|
{
|
||||||
|
_companyName = PersistentCompanyName;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -109,6 +118,7 @@
|
|||||||
if (tenantInfo?.IsTenant == true && !string.IsNullOrEmpty(tenantInfo.Name))
|
if (tenantInfo?.IsTenant == true && !string.IsNullOrEmpty(tenantInfo.Name))
|
||||||
{
|
{
|
||||||
_companyName = tenantInfo.Name;
|
_companyName = tenantInfo.Name;
|
||||||
|
PersistentCompanyName = _companyName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -116,6 +126,7 @@
|
|||||||
// Ignore background error
|
// Ignore background error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -152,6 +152,12 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<User>? PersistentUsers { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<TenantStats>? PersistentTenants { get; set; }
|
||||||
|
|
||||||
private List<User> _users = [];
|
private List<User> _users = [];
|
||||||
private List<TenantStats> _tenants = [];
|
private List<TenantStats> _tenants = [];
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
@@ -161,23 +167,35 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
if (PersistentUsers != null)
|
||||||
|
{
|
||||||
|
_users = PersistentUsers;
|
||||||
|
_tenants = PersistentTenants ?? [];
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
var claim = (await AuthStateProvider.GetAuthenticationStateAsync())
|
var claim = (await AuthStateProvider.GetAuthenticationStateAsync())
|
||||||
.User.FindFirst(ClaimTypes.NameIdentifier);
|
.User.FindFirst(ClaimTypes.NameIdentifier);
|
||||||
if (claim == null) return;
|
if (claim == null) return;
|
||||||
|
|
||||||
UserNotificationService.OnUsersChanged += RefreshUsers;
|
UserNotificationService.OnUsersChanged += RefreshUsers;
|
||||||
|
|
||||||
|
if (PersistentUsers == null)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_users = await AuthService.GetAllUsersAsync();
|
_users = await AuthService.GetAllUsersAsync();
|
||||||
_tenants = await Http.GetFromJsonAsync<List<TenantStats>>("api/superadmin/tenants") ?? [];
|
_tenants = await Http.GetFromJsonAsync<List<TenantStats>>("api/superadmin/tenants") ?? [];
|
||||||
|
|
||||||
|
PersistentUsers = _users;
|
||||||
|
PersistentTenants = _tenants;
|
||||||
|
_loading = false;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Snackbar.Add($"Fehler beim Laden der Daten: {ex.Message}", Severity.Error);
|
Snackbar.Add($"Fehler beim Laden der Daten: {ex.Message}", Severity.Error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
_loading = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RefreshUsers()
|
private async Task RefreshUsers()
|
||||||
|
|||||||
@@ -60,15 +60,19 @@
|
|||||||
|
|
||||||
public static readonly List<Release> Releases =
|
public static readonly List<Release> Releases =
|
||||||
[
|
[
|
||||||
new("1.5", "25.06.2026", true,
|
new("1.7", "27.06.2026", true,
|
||||||
|
[
|
||||||
|
new("Neu", "Excel-Export"),
|
||||||
|
new("Upgrade", "Besseres Page-Loading")
|
||||||
|
], Highlighted: true),
|
||||||
|
new("1.6", "25.06.2026", true,
|
||||||
[
|
[
|
||||||
new("Neu", "Userprofil angelegt"),
|
new("Neu", "Userprofil angelegt"),
|
||||||
new("Upgrade", "Früheste Gehenszeit wird angezeigt"),
|
new("Upgrade", "Früheste Gehenszeit wird angezeigt"),
|
||||||
new("Upgrade", "Pausen werden dynamisch berechnet"),
|
new("Upgrade", "Pausen werden dynamisch berechnet"),
|
||||||
new("Neu", "Excel-Export"),
|
|
||||||
new("Neu", "Multi-Tenant Integration"),
|
new("Neu", "Multi-Tenant Integration"),
|
||||||
new("Upgrade", "Verbesserte Single-User Ansicht")
|
new("Upgrade", "Verbesserte Single-User Ansicht")
|
||||||
], Highlighted: true),
|
]),
|
||||||
new("1.4", "08.06.2026", true,
|
new("1.4", "08.06.2026", true,
|
||||||
[
|
[
|
||||||
new("Neu", "Timebot implementiert"),
|
new("Neu", "Timebot implementiert"),
|
||||||
|
|||||||
@@ -183,6 +183,18 @@ else
|
|||||||
@code {
|
@code {
|
||||||
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public AppSettings? PersistentSettings { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<PublicHoliday>? PersistentHolidays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentSubLabel { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public int? PersistentYear { get; set; }
|
||||||
|
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
private int _year = DateTime.Today.Year;
|
private int _year = DateTime.Today.Year;
|
||||||
private List<PublicHoliday> _holidays = [];
|
private List<PublicHoliday> _holidays = [];
|
||||||
@@ -193,16 +205,39 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
if (PersistentSettings != null && PersistentHolidays != null)
|
||||||
|
{
|
||||||
|
_settings = PersistentSettings;
|
||||||
|
_holidays = PersistentHolidays;
|
||||||
|
_subLabel = PersistentSubLabel ?? "";
|
||||||
|
_year = PersistentYear ?? DateTime.Today.Year;
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||||
var claim = authState.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
|
var claim = authState.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
|
||||||
if (claim != null)
|
if (claim != null)
|
||||||
{
|
{
|
||||||
_userId = int.Parse(claim.Value);
|
_userId = int.Parse(claim.Value);
|
||||||
|
|
||||||
|
if (PersistentSettings == null || PersistentHolidays == null)
|
||||||
|
{
|
||||||
_settings = await TrackerService.GetSettingsAsync(_userId);
|
_settings = await TrackerService.GetSettingsAsync(_userId);
|
||||||
|
await LoadHolidays();
|
||||||
|
|
||||||
|
PersistentSettings = _settings;
|
||||||
|
PersistentHolidays = _holidays;
|
||||||
|
PersistentSubLabel = _subLabel;
|
||||||
|
PersistentYear = _year;
|
||||||
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
await LoadHolidays();
|
await LoadHolidays();
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LoadHolidays()
|
private async Task LoadHolidays()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -388,6 +388,30 @@ else
|
|||||||
@code {
|
@code {
|
||||||
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public AppSettings? PersistentSettings { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<DayVm>? PersistentDays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public TimeSpan? PersistentTotalOvertime { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public Dictionary<DateOnly, string>? PersistentHolidays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public int? PersistentHolidayYear { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<VacationDay>? PersistentVacations { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentWeekLabel { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentWeekSubLabel { get; set; }
|
||||||
|
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
private int _userId;
|
private int _userId;
|
||||||
private DateOnly _monday;
|
private DateOnly _monday;
|
||||||
@@ -409,11 +433,27 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
if (PersistentSettings != null && PersistentDays != null && PersistentTotalOvertime != null)
|
||||||
|
{
|
||||||
|
_settings = PersistentSettings;
|
||||||
|
_days = PersistentDays;
|
||||||
|
_totalOvertime = PersistentTotalOvertime.Value;
|
||||||
|
_holidays = PersistentHolidays ?? [];
|
||||||
|
_holidayYear = PersistentHolidayYear ?? -1;
|
||||||
|
_vacations = PersistentVacations ?? [];
|
||||||
|
_weekLabel = PersistentWeekLabel ?? "";
|
||||||
|
_weekSubLabel = PersistentWeekSubLabel ?? "";
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||||
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
||||||
if (claim == null) return; // Prerender-Pass – Circuit noch nicht authentifiziert
|
if (claim == null) return; // Prerender-Pass – Circuit noch nicht authentifiziert
|
||||||
_userId = int.Parse(claim.Value);
|
_userId = int.Parse(claim.Value);
|
||||||
_monday = GetMonday(DateOnly.FromDateTime(DateTime.Today));
|
_monday = GetMonday(DateOnly.FromDateTime(DateTime.Today));
|
||||||
|
|
||||||
|
if (PersistentSettings == null || PersistentDays == null || PersistentTotalOvertime == null)
|
||||||
|
{
|
||||||
_settings = await TrackerService.GetSettingsAsync(_userId);
|
_settings = await TrackerService.GetSettingsAsync(_userId);
|
||||||
|
|
||||||
var loadWeekTask = LoadWeek();
|
var loadWeekTask = LoadWeek();
|
||||||
@@ -422,6 +462,17 @@ else
|
|||||||
await Task.WhenAll(loadWeekTask, overtimeTask);
|
await Task.WhenAll(loadWeekTask, overtimeTask);
|
||||||
_totalOvertime = await overtimeTask;
|
_totalOvertime = await overtimeTask;
|
||||||
|
|
||||||
|
PersistentSettings = _settings;
|
||||||
|
PersistentDays = _days;
|
||||||
|
PersistentTotalOvertime = _totalOvertime;
|
||||||
|
PersistentHolidays = _holidays;
|
||||||
|
PersistentHolidayYear = _holidayYear;
|
||||||
|
PersistentVacations = _vacations;
|
||||||
|
PersistentWeekLabel = _weekLabel;
|
||||||
|
PersistentWeekSubLabel = _weekSubLabel;
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var showOnb = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "showOnboarding");
|
var showOnb = await JSRuntime.InvokeAsync<string>("localStorage.getItem", "showOnboarding");
|
||||||
@@ -431,8 +482,6 @@ else
|
|||||||
{
|
{
|
||||||
// Ignored during prerendering/SSR
|
// Ignored during prerendering/SSR
|
||||||
}
|
}
|
||||||
|
|
||||||
_loading = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleOnboardingFinished()
|
private async Task HandleOnboardingFinished()
|
||||||
@@ -693,7 +742,7 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── ViewModels ────────────────────────────────────────────────
|
// ── ViewModels ────────────────────────────────────────────────
|
||||||
private sealed class DayVm
|
public sealed class DayVm
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int UserId { get; set; }
|
public int UserId { get; set; }
|
||||||
@@ -743,7 +792,7 @@ else
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class BreakVm
|
public sealed class BreakVm
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public TimeSpan? Start { get; set; }
|
public TimeSpan? Start { get; set; }
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<PageTitle>@GetPageTitle()</PageTitle>
|
<PageTitle>@GetPageTitle()</PageTitle>
|
||||||
|
|
||||||
@if (_tenantInfo == null)
|
@if (TenantInfo == null)
|
||||||
{
|
{
|
||||||
@* Loading indicator while resolving Tenant *@
|
@* Loading indicator while resolving Tenant *@
|
||||||
<MudContainer MaxWidth="MaxWidth.Small" Class="mt-16 text-center">
|
<MudContainer MaxWidth="MaxWidth.Small" Class="mt-16 text-center">
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
<MudText Class="mt-4" Color="Color.Secondary">Lade Timetracker…</MudText>
|
<MudText Class="mt-4" Color="Color.Secondary">Lade Timetracker…</MudText>
|
||||||
</MudContainer>
|
</MudContainer>
|
||||||
}
|
}
|
||||||
else if (_tenantInfo.IsTenant && !_tenantInfo.IsApproved)
|
else if (TenantInfo.IsTenant && !TenantInfo.IsApproved)
|
||||||
{
|
{
|
||||||
@* Pending Approval Screen *@
|
@* Pending Approval Screen *@
|
||||||
<MudContainer MaxWidth="MaxWidth.Small" Class="mt-16">
|
<MudContainer MaxWidth="MaxWidth.Small" Class="mt-16">
|
||||||
@@ -34,7 +34,7 @@ else if (_tenantInfo.IsTenant && !_tenantInfo.IsApproved)
|
|||||||
Class="mb-4" />
|
Class="mb-4" />
|
||||||
<MudText Typo="Typo.h5" Style="font-weight: 700;" Class="mb-2">Freischaltung ausstehend</MudText>
|
<MudText Typo="Typo.h5" Style="font-weight: 700;" Class="mb-2">Freischaltung ausstehend</MudText>
|
||||||
<MudText Typo="Typo.body1" Color="Color.Secondary" Class="mb-6">
|
<MudText Typo="Typo.body1" Color="Color.Secondary" Class="mb-6">
|
||||||
Die Firma <strong>@_tenantInfo.Name</strong> wurde erfolgreich registriert.
|
Die Firma <strong>@TenantInfo.Name</strong> wurde erfolgreich registriert.
|
||||||
Der Zugang wird derzeit von unserem SuperAdmin geprüft und in Kürze freigeschaltet.
|
Der Zugang wird derzeit von unserem SuperAdmin geprüft und in Kürze freigeschaltet.
|
||||||
</MudText>
|
</MudText>
|
||||||
<MudDivider Class="my-4" />
|
<MudDivider Class="my-4" />
|
||||||
@@ -64,9 +64,9 @@ else
|
|||||||
<MudIcon Icon="@Icons.Material.Filled.AccessTime"
|
<MudIcon Icon="@Icons.Material.Filled.AccessTime"
|
||||||
Style="font-size:4rem; color:#0EA5E9" />
|
Style="font-size:4rem; color:#0EA5E9" />
|
||||||
<MudText Typo="Typo.h4" Style="font-weight:700; color:#0EA5E9">
|
<MudText Typo="Typo.h4" Style="font-weight:700; color:#0EA5E9">
|
||||||
@(_tenantInfo.IsTenant ? _tenantInfo.Name : "Timetracker SaaS")
|
@(TenantInfo.IsTenant ? TenantInfo.Name : "Timetracker SaaS")
|
||||||
</MudText>
|
</MudText>
|
||||||
@if (!_tenantInfo.IsTenant)
|
@if (!TenantInfo.IsTenant)
|
||||||
{
|
{
|
||||||
<MudText Typo="Typo.caption" Color="Color.Secondary">Zentrales Portal</MudText>
|
<MudText Typo="Typo.caption" Color="Color.Secondary">Zentrales Portal</MudText>
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ else
|
|||||||
}
|
}
|
||||||
else if (_activeTab == 1)
|
else if (_activeTab == 1)
|
||||||
{
|
{
|
||||||
@if (_tenantInfo.IsTenant)
|
@if (TenantInfo.IsTenant)
|
||||||
{
|
{
|
||||||
@* ── Employee Register Form ── *@
|
@* ── Employee Register Form ── *@
|
||||||
<MudStack Spacing="3">
|
<MudStack Spacing="3">
|
||||||
@@ -359,7 +359,7 @@ else
|
|||||||
</MudStack>
|
</MudStack>
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (!_tenantInfo.IsTenant && _activeTab != 2)
|
@if (!TenantInfo.IsTenant && _activeTab != 2)
|
||||||
{
|
{
|
||||||
<MudDivider Class="my-4" />
|
<MudDivider Class="my-4" />
|
||||||
<MudStack AlignItems="AlignItems.Center">
|
<MudStack AlignItems="AlignItems.Center">
|
||||||
@@ -378,7 +378,9 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private TenantInfo? _tenantInfo;
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public TenantInfo? TenantInfo { get; set; }
|
||||||
|
|
||||||
private int _activeTab = 0;
|
private int _activeTab = 0;
|
||||||
private string? _error;
|
private string? _error;
|
||||||
private bool _loading;
|
private bool _loading;
|
||||||
@@ -398,16 +400,19 @@ else
|
|||||||
public string? TabParam { get; set; }
|
public string? TabParam { get; set; }
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (TenantInfo is null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_tenantInfo = await Http.GetFromJsonAsync<TenantInfo>("api/tenant/current");
|
TenantInfo = await Http.GetFromJsonAsync<TenantInfo>("api/tenant/current");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Fehler beim Abrufen der TenantInfo: {ex.Message}");
|
Console.WriteLine($"Fehler beim Abrufen der TenantInfo: {ex.Message}");
|
||||||
// Fallback
|
// Fallback
|
||||||
_tenantInfo = new TenantInfo { IsTenant = false };
|
TenantInfo = new TenantInfo { IsTenant = false };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,8 +435,8 @@ else
|
|||||||
|
|
||||||
private string GetPageTitle()
|
private string GetPageTitle()
|
||||||
{
|
{
|
||||||
if (_tenantInfo == null) return "Lade…";
|
if (TenantInfo == null) return "Lade…";
|
||||||
return _tenantInfo.IsTenant ? $"Anmelden bei {_tenantInfo.Name} – Timetracker" : "Anmelden – Timetracker SaaS";
|
return TenantInfo.IsTenant ? $"Anmelden bei {TenantInfo.Name} – Timetracker" : "Anmelden – Timetracker SaaS";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetDomainSuffix()
|
private string GetDomainSuffix()
|
||||||
|
|||||||
@@ -155,6 +155,33 @@ else
|
|||||||
@code {
|
@code {
|
||||||
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public AppSettings? PersistentSettings { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<MonthDayVm>? PersistentDays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentSubLabel { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public TimeSpan? PersistentMonthNet { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public TimeSpan? PersistentMonthOvertime { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public int? PersistentRecordedWorkDays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public int? PersistentTotalWorkDays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public int? PersistentVacationCount { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public int? PersistentHolidayCount { get; set; }
|
||||||
|
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
private int _userId;
|
private int _userId;
|
||||||
private int _year = DateTime.Today.Year;
|
private int _year = DateTime.Today.Year;
|
||||||
@@ -174,14 +201,42 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
if (PersistentSettings != null && PersistentDays != null)
|
||||||
|
{
|
||||||
|
_settings = PersistentSettings;
|
||||||
|
_days = PersistentDays;
|
||||||
|
_subLabel = PersistentSubLabel ?? "";
|
||||||
|
_monthNet = PersistentMonthNet ?? TimeSpan.Zero;
|
||||||
|
_monthOvertime = PersistentMonthOvertime ?? TimeSpan.Zero;
|
||||||
|
_recordedWorkDays = PersistentRecordedWorkDays ?? 0;
|
||||||
|
_totalWorkDays = PersistentTotalWorkDays ?? 0;
|
||||||
|
_vacationCount = PersistentVacationCount ?? 0;
|
||||||
|
_holidayCount = PersistentHolidayCount ?? 0;
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||||
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
||||||
if (claim == null) return;
|
if (claim == null) return;
|
||||||
_userId = int.Parse(claim.Value);
|
_userId = int.Parse(claim.Value);
|
||||||
|
|
||||||
|
if (PersistentSettings == null || PersistentDays == null)
|
||||||
|
{
|
||||||
_settings = await TrackerService.GetSettingsAsync(_userId);
|
_settings = await TrackerService.GetSettingsAsync(_userId);
|
||||||
await LoadMonth();
|
await LoadMonth();
|
||||||
|
|
||||||
|
PersistentSettings = _settings;
|
||||||
|
PersistentDays = _days;
|
||||||
|
PersistentSubLabel = _subLabel;
|
||||||
|
PersistentMonthNet = _monthNet;
|
||||||
|
PersistentMonthOvertime = _monthOvertime;
|
||||||
|
PersistentRecordedWorkDays = _recordedWorkDays;
|
||||||
|
PersistentTotalWorkDays = _totalWorkDays;
|
||||||
|
PersistentVacationCount = _vacationCount;
|
||||||
|
PersistentHolidayCount = _holidayCount;
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LoadMonth()
|
private async Task LoadMonth()
|
||||||
{
|
{
|
||||||
@@ -317,7 +372,7 @@ else
|
|||||||
else Chip("Ausstehend", "#CFD8DC");
|
else Chip("Ausstehend", "#CFD8DC");
|
||||||
};
|
};
|
||||||
|
|
||||||
private sealed class MonthDayVm
|
public sealed class MonthDayVm
|
||||||
{
|
{
|
||||||
public DateOnly Date { get; set; }
|
public DateOnly Date { get; set; }
|
||||||
public TimeOnly? StartTime { get; set; }
|
public TimeOnly? StartTime { get; set; }
|
||||||
|
|||||||
@@ -163,6 +163,21 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public AppSettings? PersistentSettings { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentUsername { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentNewUsername { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public bool? PersistentIsAdmin { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public TimeSpan? PersistentOvertime { get; set; }
|
||||||
|
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
private int _userId;
|
private int _userId;
|
||||||
private string _username = "";
|
private string _username = "";
|
||||||
@@ -184,19 +199,39 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
if (PersistentSettings != null)
|
||||||
|
{
|
||||||
|
_settings = PersistentSettings;
|
||||||
|
_username = PersistentUsername ?? "";
|
||||||
|
_newUsername = PersistentNewUsername ?? "";
|
||||||
|
_isAdmin = PersistentIsAdmin ?? false;
|
||||||
|
_overtime = PersistentOvertime ?? TimeSpan.Zero;
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||||
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
||||||
if (claim == null) return;
|
if (claim == null) return;
|
||||||
|
|
||||||
_userId = int.Parse(claim.Value);
|
_userId = int.Parse(claim.Value);
|
||||||
|
|
||||||
|
if (PersistentSettings == null)
|
||||||
|
{
|
||||||
_username = authState.User.Identity?.Name ?? "";
|
_username = authState.User.Identity?.Name ?? "";
|
||||||
_newUsername = _username;
|
_newUsername = _username;
|
||||||
_isAdmin = _username.Equals("marc", StringComparison.OrdinalIgnoreCase);
|
_isAdmin = _username.Equals("marc", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
_settings = await TrackerService.GetSettingsAsync(_userId);
|
_settings = await TrackerService.GetSettingsAsync(_userId);
|
||||||
_overtime = await TrackerService.GetTotalOvertimeAsync(_userId, _settings);
|
_overtime = await TrackerService.GetTotalOvertimeAsync(_userId, _settings);
|
||||||
|
|
||||||
|
PersistentSettings = _settings;
|
||||||
|
PersistentUsername = _username;
|
||||||
|
PersistentNewUsername = _newUsername;
|
||||||
|
PersistentIsAdmin = _isAdmin;
|
||||||
|
PersistentOvertime = _overtime;
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string GetInitials(string? name)
|
private string GetInitials(string? name)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -511,6 +511,27 @@ else
|
|||||||
@code {
|
@code {
|
||||||
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public AppSettings? PersistentSettings { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public TenantInfo? PersistentTenantInfo { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<VacationDay>? PersistentVacationDays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<PublicHoliday>? PersistentHolHolidays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentTenantName { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentTenantPrimaryColor { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentTenantSecondaryColor { get; set; }
|
||||||
|
|
||||||
private AppSettings? _settings;
|
private AppSettings? _settings;
|
||||||
private int _userId;
|
private int _userId;
|
||||||
private bool _isTenantAdmin;
|
private bool _isTenantAdmin;
|
||||||
@@ -571,13 +592,31 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
if (PersistentSettings != null)
|
||||||
|
{
|
||||||
|
_settings = PersistentSettings;
|
||||||
|
_tenantInfo = PersistentTenantInfo;
|
||||||
|
_vacationDays = PersistentVacationDays ?? [];
|
||||||
|
_holHolidays = PersistentHolHolidays ?? [];
|
||||||
|
_tenantName = PersistentTenantName ?? "";
|
||||||
|
_tenantPrimaryColor = PersistentTenantPrimaryColor ?? "#0EA5E9";
|
||||||
|
_tenantSecondaryColor = PersistentTenantSecondaryColor ?? "#0EA5E9";
|
||||||
|
}
|
||||||
|
|
||||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||||
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
||||||
if (claim == null) return;
|
if (claim == null) return;
|
||||||
_userId = int.Parse(claim.Value);
|
_userId = int.Parse(claim.Value);
|
||||||
|
|
||||||
|
if (PersistentSettings != null)
|
||||||
|
{
|
||||||
|
_isTenantAdmin = authState.User.IsInRole("TenantAdmin") || authState.User.HasClaim("IsTenantAdmin", "true");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_isTenantAdmin = authState.User.IsInRole("TenantAdmin") || authState.User.HasClaim("IsTenantAdmin", "true");
|
||||||
_settings = await TrackerService.GetSettingsAsync(_userId);
|
_settings = await TrackerService.GetSettingsAsync(_userId);
|
||||||
|
|
||||||
_isTenantAdmin = authState.User.IsInRole("TenantAdmin") || authState.User.HasClaim("IsTenantAdmin", "true");
|
|
||||||
if (_isTenantAdmin)
|
if (_isTenantAdmin)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -601,6 +640,15 @@ else
|
|||||||
|
|
||||||
await Task.WhenAll(loadVacationsTask, loadHolidaysTask);
|
await Task.WhenAll(loadVacationsTask, loadHolidaysTask);
|
||||||
_holHolidays = await loadHolidaysTask;
|
_holHolidays = await loadHolidaysTask;
|
||||||
|
|
||||||
|
PersistentSettings = _settings;
|
||||||
|
PersistentTenantInfo = _tenantInfo;
|
||||||
|
PersistentVacationDays = _vacationDays;
|
||||||
|
PersistentHolHolidays = _holHolidays;
|
||||||
|
PersistentTenantName = _tenantName;
|
||||||
|
PersistentTenantPrimaryColor = _tenantPrimaryColor;
|
||||||
|
PersistentTenantSecondaryColor = _tenantSecondaryColor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadVacations()
|
private async Task LoadVacations()
|
||||||
|
|||||||
@@ -324,6 +324,27 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public AppSettings? PersistentSettings { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<DayStat>? PersistentDays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public TimeSpan? PersistentTotalOvertime { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public double? PersistentWeekWorkedHours { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public double? PersistentWeekTargetHours { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public double? PersistentWeekOvertimeHours { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public double? PersistentMaxHoursValue { get; set; }
|
||||||
|
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
private int _userId;
|
private int _userId;
|
||||||
private AppSettings _settings = new();
|
private AppSettings _settings = new();
|
||||||
@@ -349,11 +370,25 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
if (PersistentSettings != null && PersistentDays != null)
|
||||||
|
{
|
||||||
|
_settings = PersistentSettings;
|
||||||
|
_days = PersistentDays;
|
||||||
|
_totalOvertime = PersistentTotalOvertime ?? TimeSpan.Zero;
|
||||||
|
_weekWorkedHours = PersistentWeekWorkedHours ?? 0.0;
|
||||||
|
_weekTargetHours = PersistentWeekTargetHours ?? 0.0;
|
||||||
|
_weekOvertimeHours = PersistentWeekOvertimeHours ?? 0.0;
|
||||||
|
_maxHoursValue = PersistentMaxHoursValue ?? 10.0;
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||||
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
||||||
if (claim == null) return;
|
if (claim == null) return;
|
||||||
_userId = int.Parse(claim.Value);
|
_userId = int.Parse(claim.Value);
|
||||||
|
|
||||||
|
if (PersistentSettings == null || PersistentDays == null)
|
||||||
|
{
|
||||||
_settings = await TrackerService.GetSettingsAsync(_userId);
|
_settings = await TrackerService.GetSettingsAsync(_userId);
|
||||||
|
|
||||||
var today = DateOnly.FromDateTime(DateTime.Today);
|
var today = DateOnly.FromDateTime(DateTime.Today);
|
||||||
@@ -426,8 +461,16 @@ else
|
|||||||
var maxWorked = _days.Max(d => d.WorkedHours);
|
var maxWorked = _days.Max(d => d.WorkedHours);
|
||||||
_maxHoursValue = Math.Max(10.0, Math.Max(maxWorked, _settings.DailyTargetHours));
|
_maxHoursValue = Math.Max(10.0, Math.Max(maxWorked, _settings.DailyTargetHours));
|
||||||
|
|
||||||
|
PersistentSettings = _settings;
|
||||||
|
PersistentDays = _days;
|
||||||
|
PersistentTotalOvertime = _totalOvertime;
|
||||||
|
PersistentWeekWorkedHours = _weekWorkedHours;
|
||||||
|
PersistentWeekTargetHours = _weekTargetHours;
|
||||||
|
PersistentWeekOvertimeHours = _weekOvertimeHours;
|
||||||
|
PersistentMaxHoursValue = _maxHoursValue;
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static DateOnly GetMonday(DateOnly date)
|
private static DateOnly GetMonday(DateOnly date)
|
||||||
{
|
{
|
||||||
@@ -468,7 +511,7 @@ else
|
|||||||
NavigationManager.NavigateTo($"api/tracker/export/year?year={_exportYear}", forceLoad: true);
|
NavigationManager.NavigateTo($"api/tracker/export/year?year={_exportYear}", forceLoad: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class DayStat
|
public sealed class DayStat
|
||||||
{
|
{
|
||||||
public DateOnly Date { get; set; }
|
public DateOnly Date { get; set; }
|
||||||
public string DayName { get; set; } = "";
|
public string DayName { get; set; } = "";
|
||||||
|
|||||||
@@ -167,13 +167,24 @@ else
|
|||||||
}
|
}
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<TenantStats>? PersistentTenants { get; set; }
|
||||||
|
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
private List<TenantStats> _tenants = [];
|
private List<TenantStats> _tenants = [];
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
|
{
|
||||||
|
if (PersistentTenants != null)
|
||||||
|
{
|
||||||
|
_tenants = PersistentTenants;
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
await LoadTenants();
|
await LoadTenants();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LoadTenants()
|
private async Task LoadTenants()
|
||||||
{
|
{
|
||||||
@@ -181,6 +192,7 @@ else
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_tenants = await Http.GetFromJsonAsync<List<TenantStats>>("api/superadmin/tenants") ?? [];
|
_tenants = await Http.GetFromJsonAsync<List<TenantStats>>("api/superadmin/tenants") ?? [];
|
||||||
|
PersistentTenants = _tenants;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -226,6 +226,27 @@ else
|
|||||||
@code {
|
@code {
|
||||||
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public AppSettings? PersistentSettings { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public Dictionary<DateOnly, string>? PersistentHolidays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<DateOnly>? PersistentVacationList { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public int? PersistentRemainingDays { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public List<Suggestion>? PersistentSuggestions { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public string? PersistentSubLabel { get; set; }
|
||||||
|
|
||||||
|
[PersistentState(AllowUpdates = true)]
|
||||||
|
public int? PersistentYear { get; set; }
|
||||||
|
|
||||||
private bool _loading = true;
|
private bool _loading = true;
|
||||||
private int _year = DateTime.Today.Year;
|
private int _year = DateTime.Today.Year;
|
||||||
private AppSettings _settings = new();
|
private AppSettings _settings = new();
|
||||||
@@ -238,14 +259,38 @@ else
|
|||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
|
if (PersistentSettings != null && PersistentSuggestions != null)
|
||||||
|
{
|
||||||
|
_settings = PersistentSettings;
|
||||||
|
_holidays = PersistentHolidays ?? [];
|
||||||
|
_vacationSet = (PersistentVacationList ?? []).ToHashSet();
|
||||||
|
_remainingDays = PersistentRemainingDays ?? 0;
|
||||||
|
_suggestions = PersistentSuggestions;
|
||||||
|
_subLabel = PersistentSubLabel ?? "";
|
||||||
|
_year = PersistentYear ?? DateTime.Today.Year;
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
var authState = await AuthStateProvider.GetAuthenticationStateAsync();
|
||||||
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
|
||||||
if (claim == null) return;
|
if (claim == null) return;
|
||||||
_userId = int.Parse(claim.Value);
|
_userId = int.Parse(claim.Value);
|
||||||
|
|
||||||
|
if (PersistentSettings == null || PersistentSuggestions == null)
|
||||||
|
{
|
||||||
_settings = await TrackerService.GetSettingsAsync(_userId);
|
_settings = await TrackerService.GetSettingsAsync(_userId);
|
||||||
await LoadYear();
|
await LoadYear();
|
||||||
|
|
||||||
|
PersistentSettings = _settings;
|
||||||
|
PersistentHolidays = _holidays;
|
||||||
|
PersistentVacationList = _vacationSet.ToList();
|
||||||
|
PersistentRemainingDays = _remainingDays;
|
||||||
|
PersistentSuggestions = _suggestions;
|
||||||
|
PersistentSubLabel = _subLabel;
|
||||||
|
PersistentYear = _year;
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task LoadYear()
|
private async Task LoadYear()
|
||||||
{
|
{
|
||||||
@@ -283,7 +328,7 @@ else
|
|||||||
// ── Algorithmus ──────────────────────────────────────────────────────
|
// ── Algorithmus ──────────────────────────────────────────────────────
|
||||||
private enum DayKind { Free, WorkAvailable, WorkTaken }
|
private enum DayKind { Free, WorkAvailable, WorkTaken }
|
||||||
|
|
||||||
private sealed record Suggestion(
|
public sealed record Suggestion(
|
||||||
DateOnly SpanStart,
|
DateOnly SpanStart,
|
||||||
DateOnly SpanEnd,
|
DateOnly SpanEnd,
|
||||||
List<DateOnly> VacationDaysToTake,
|
List<DateOnly> VacationDaysToTake,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Net.Http.Json;
|
using System.Net.Http.Json;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
using Microsoft.AspNetCore.Components.Authorization;
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using timetracker.Shared;
|
using timetracker.Shared;
|
||||||
|
|
||||||
@@ -8,12 +9,14 @@ namespace timetracker.Client.Services;
|
|||||||
public class HostAuthenticationStateProvider : AuthenticationStateProvider
|
public class HostAuthenticationStateProvider : AuthenticationStateProvider
|
||||||
{
|
{
|
||||||
private readonly HttpClient _http;
|
private readonly HttpClient _http;
|
||||||
|
private readonly PersistentComponentState _state;
|
||||||
private static readonly ClaimsPrincipal Anonymous = new(new ClaimsIdentity());
|
private static readonly ClaimsPrincipal Anonymous = new(new ClaimsIdentity());
|
||||||
private ClaimsPrincipal? _currentUser;
|
private ClaimsPrincipal? _currentUser;
|
||||||
|
|
||||||
public HostAuthenticationStateProvider(HttpClient http)
|
public HostAuthenticationStateProvider(HttpClient http, PersistentComponentState state)
|
||||||
{
|
{
|
||||||
_http = http;
|
_http = http;
|
||||||
|
_state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
|
||||||
@@ -23,14 +26,14 @@ public class HostAuthenticationStateProvider : AuthenticationStateProvider
|
|||||||
return new AuthenticationState(_currentUser);
|
return new AuthenticationState(_currentUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
if (_state.TryTakeFromJson<UserInfo>("UserInfoState", out var userInfo) && userInfo != null)
|
||||||
{
|
{
|
||||||
var response = await _http.GetAsync("api/auth/me");
|
if (!userInfo.IsAuthenticated)
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
var userInfo = await response.Content.ReadFromJsonAsync<UserInfo>();
|
|
||||||
if (userInfo != null)
|
|
||||||
{
|
{
|
||||||
|
_currentUser = Anonymous;
|
||||||
|
return new AuthenticationState(_currentUser);
|
||||||
|
}
|
||||||
|
|
||||||
var claims = new[]
|
var claims = new[]
|
||||||
{
|
{
|
||||||
new Claim(ClaimTypes.NameIdentifier, userInfo.Id.ToString()),
|
new Claim(ClaimTypes.NameIdentifier, userInfo.Id.ToString()),
|
||||||
@@ -42,6 +45,26 @@ public class HostAuthenticationStateProvider : AuthenticationStateProvider
|
|||||||
_currentUser = new ClaimsPrincipal(identity);
|
_currentUser = new ClaimsPrincipal(identity);
|
||||||
return new AuthenticationState(_currentUser);
|
return new AuthenticationState(_currentUser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response = await _http.GetAsync("api/auth/me");
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
var apiUserInfo = await response.Content.ReadFromJsonAsync<UserInfo>();
|
||||||
|
if (apiUserInfo != null)
|
||||||
|
{
|
||||||
|
var claims = new[]
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.NameIdentifier, apiUserInfo.Id.ToString()),
|
||||||
|
new Claim(ClaimTypes.Name, apiUserInfo.Username),
|
||||||
|
new Claim("IsTenantAdmin", apiUserInfo.IsTenantAdmin ? "true" : "false"),
|
||||||
|
new Claim(ClaimTypes.Role, apiUserInfo.IsTenantAdmin ? "TenantAdmin" : "Employee")
|
||||||
|
};
|
||||||
|
var identity = new ClaimsIdentity(claims, "Cookie");
|
||||||
|
_currentUser = new ClaimsPrincipal(identity);
|
||||||
|
return new AuthenticationState(_currentUser);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<Routes />
|
<Routes />
|
||||||
|
<persist-component-state />
|
||||||
<script src="@Assets["_framework/blazor.web.js"]"></script>
|
<script src="@Assets["_framework/blazor.web.js"]"></script>
|
||||||
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
<script src="_content/MudBlazor/MudBlazor.min.js"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using Microsoft.AspNetCore.Components;
|
||||||
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Components.Server;
|
||||||
|
using Microsoft.AspNetCore.Components.Web;
|
||||||
|
using timetracker.Shared;
|
||||||
|
|
||||||
|
namespace timetracker.Server;
|
||||||
|
|
||||||
|
public class PersistingServerAuthenticationStateProvider : ServerAuthenticationStateProvider, IDisposable
|
||||||
|
{
|
||||||
|
private readonly PersistentComponentState _state;
|
||||||
|
private readonly PersistingComponentStateSubscription _subscription;
|
||||||
|
|
||||||
|
public PersistingServerAuthenticationStateProvider(PersistentComponentState state)
|
||||||
|
{
|
||||||
|
_state = state;
|
||||||
|
_subscription = state.RegisterOnPersisting(PersistAuthenticationState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PersistAuthenticationState()
|
||||||
|
{
|
||||||
|
var authState = await GetAuthenticationStateAsync();
|
||||||
|
var user = authState.User;
|
||||||
|
|
||||||
|
if (user.Identity?.IsAuthenticated == true)
|
||||||
|
{
|
||||||
|
var idClaim = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
||||||
|
var name = user.Identity.Name;
|
||||||
|
var isAdminClaim = user.FindFirst("IsTenantAdmin")?.Value;
|
||||||
|
|
||||||
|
if (idClaim != null && name != null)
|
||||||
|
{
|
||||||
|
var userInfo = new UserInfo
|
||||||
|
{
|
||||||
|
Id = int.Parse(idClaim),
|
||||||
|
Username = name,
|
||||||
|
IsTenantAdmin = isAdminClaim == "true",
|
||||||
|
IsAuthenticated = true
|
||||||
|
};
|
||||||
|
_state.PersistAsJson("UserInfoState", userInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var userInfo = new UserInfo
|
||||||
|
{
|
||||||
|
IsAuthenticated = false
|
||||||
|
};
|
||||||
|
_state.PersistAsJson("UserInfoState", userInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_subscription.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,8 +7,10 @@ using Microsoft.AspNetCore.Authentication.Cookies;
|
|||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.AspNetCore.Components.Authorization;
|
||||||
using MudBlazor.Services;
|
using MudBlazor.Services;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using timetracker.Server;
|
||||||
using timetracker.Server.Components;
|
using timetracker.Server.Components;
|
||||||
using timetracker.Data;
|
using timetracker.Data;
|
||||||
using timetracker.Shared;
|
using timetracker.Shared;
|
||||||
@@ -68,6 +70,7 @@ builder.Services.AddAuthorization(options =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
builder.Services.AddCascadingAuthenticationState();
|
builder.Services.AddCascadingAuthenticationState();
|
||||||
|
builder.Services.AddScoped<AuthenticationStateProvider, PersistingServerAuthenticationStateProvider>();
|
||||||
builder.Services.AddHttpContextAccessor();
|
builder.Services.AddHttpContextAccessor();
|
||||||
|
|
||||||
builder.Services.AddTransient<ITenantProvider, TenantProvider>();
|
builder.Services.AddTransient<ITenantProvider, TenantProvider>();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,4 +5,5 @@ public class UserInfo
|
|||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Username { get; set; } = "";
|
public string Username { get; set; } = "";
|
||||||
public bool IsTenantAdmin { get; set; }
|
public bool IsTenantAdmin { get; set; }
|
||||||
|
public bool IsAuthenticated { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user