color Changes

This commit is contained in:
Viperion 2025-06-23 07:13:06 +02:00
parent b617d39c8f
commit 549ab3e53b
13 changed files with 209 additions and 101 deletions

View File

@ -1,5 +0,0 @@
namespace ChronoFlow.Controller;
public class Class1
{
}

View File

@ -1,5 +0,0 @@
namespace ChronoFlow.Model;
public class Class1
{
}

View File

@ -23,5 +23,6 @@ namespace ChronoFlow.Model
OriginalUsername = ""; OriginalUsername = "";
} }
public DateTime LetzterLogin { get; set; } = DateTime.MinValue; public DateTime LetzterLogin { get; set; } = DateTime.MinValue;
public DateTime VorletzterLogin { get; set; }
} }
} }

View File

@ -1,5 +0,0 @@
namespace ChronoFlow.Persistence;
public class Class1
{
}

View File

@ -23,6 +23,8 @@ namespace ChronoFlow.Persistence
// IMMER prüfen, auch nach neuem Erstellen // IMMER prüfen, auch nach neuem Erstellen
PrüfeUndErweitereDatenbank(); PrüfeUndErweitereDatenbank();
_ = StelleDatenbankstrukturSicherAsync(); // Async-Aufruf ignorieren
} }
private void ErstelleDatenbank() private void ErstelleDatenbank()
@ -92,6 +94,8 @@ namespace ChronoFlow.Persistence
AddColumnIfMissing(connection, "Benutzer", "Mitarbeitennummer", "TEXT"); AddColumnIfMissing(connection, "Benutzer", "Mitarbeitennummer", "TEXT");
AddColumnIfMissing(connection, "Benutzer", "Abteilung", "TEXT"); AddColumnIfMissing(connection, "Benutzer", "Abteilung", "TEXT");
AddColumnIfMissing(connection, "Benutzer", "MussPasswortAendern", "INTEGER DEFAULT 1"); AddColumnIfMissing(connection, "Benutzer", "MussPasswortAendern", "INTEGER DEFAULT 1");
AddColumnIfMissing(connection, "Benutzer", "LetzterLogin", "TEXT");
AddColumnIfMissing(connection, "Benutzer", "VorletzterLogin", "TEXT");
AddColumnIfMissing(connection, "Zeiteintraege", "LetzteBearbeitung", "TEXT"); AddColumnIfMissing(connection, "Zeiteintraege", "LetzteBearbeitung", "TEXT");
} }
@ -158,11 +162,24 @@ namespace ChronoFlow.Persistence
connection.Open(); connection.Open();
var cmd = connection.CreateCommand(); var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT Id, Username, Password, Role, Mitarbeitennummer, Abteilung, MussPasswortAendern FROM Benutzer;"; cmd.CommandText = @"
SELECT Id, Username, Password, Role, Mitarbeitennummer, Abteilung, MussPasswortAendern, LetzterLogin, VorletzterLogin
FROM Benutzer;
";
using var reader = cmd.ExecuteReader(); using var reader = cmd.ExecuteReader();
while (reader.Read()) while (reader.Read())
{ {
// Absicherungen für mögliche NULL- oder ungültige Werte:
var letzterLogin = DateTime.MinValue;
var vorletzterLogin = DateTime.MinValue;
if (!reader.IsDBNull(7))
DateTime.TryParse(reader.GetString(7), out letzterLogin);
if (!reader.IsDBNull(8))
DateTime.TryParse(reader.GetString(8), out vorletzterLogin);
benutzerListe.Add(new User benutzerListe.Add(new User
{ {
Id = reader.GetInt32(0), Id = reader.GetInt32(0),
@ -172,6 +189,8 @@ namespace ChronoFlow.Persistence
Mitarbeiternummer = reader.IsDBNull(4) ? "" : reader.GetString(4), Mitarbeiternummer = reader.IsDBNull(4) ? "" : reader.GetString(4),
Abteilung = reader.IsDBNull(5) ? "" : reader.GetString(5), Abteilung = reader.IsDBNull(5) ? "" : reader.GetString(5),
MussPasswortAendern = reader.GetInt32(6) == 1, MussPasswortAendern = reader.GetInt32(6) == 1,
LetzterLogin = letzterLogin,
VorletzterLogin = vorletzterLogin,
OriginalUsername = reader.GetString(1) OriginalUsername = reader.GetString(1)
}); });
} }
@ -179,6 +198,7 @@ namespace ChronoFlow.Persistence
return benutzerListe; return benutzerListe;
} }
public void UpdateBenutzer(User benutzer) public void UpdateBenutzer(User benutzer)
{ {
using var connection = new SqliteConnection($"Data Source={_dbPath}"); using var connection = new SqliteConnection($"Data Source={_dbPath}");
@ -468,6 +488,26 @@ VALUES
Console.WriteLine($"🔒 Passwort für Benutzer '{username}' zurückgesetzt (Rows affected: {rowsAffected})"); Console.WriteLine($"🔒 Passwort für Benutzer '{username}' zurückgesetzt (Rows affected: {rowsAffected})");
} }
public void UpdateLoginZeiten(User user)
{
using var connection = new SqliteConnection($"Data Source={_dbPath}");
connection.Open();
var cmd = connection.CreateCommand();
cmd.CommandText = @"
UPDATE Benutzer
SET LetzterLogin = $LetzterLogin,
VorletzterLogin = $VorletzterLogin
WHERE Username = $Username;
";
cmd.Parameters.AddWithValue("$LetzterLogin", user.LetzterLogin.ToString("o"));
cmd.Parameters.AddWithValue("$VorletzterLogin", user.VorletzterLogin.ToString("o"));
cmd.Parameters.AddWithValue("$Username", user.Username);
cmd.ExecuteNonQuery();
}
public async Task<List<Zeiteintrag>> GetEintraegeFuerMitarbeiterAsync(string name) public async Task<List<Zeiteintrag>> GetEintraegeFuerMitarbeiterAsync(string name)
{ {
var eintraege = new List<Zeiteintrag>(); var eintraege = new List<Zeiteintrag>();
@ -504,6 +544,43 @@ VALUES
return eintraege; return eintraege;
} }
public async Task StelleDatenbankstrukturSicherAsync()
{
using var connection = new SqliteConnection($"Data Source={_dbPath}");
await connection.OpenAsync();
//Überprüfung ob die Spalte "Voletzter Login" bereits besteht
var checkCmd = connection.CreateCommand();
checkCmd.CommandText = "PRAGMA table_info(Benutzer);";
var reader = await checkCmd.ExecuteReaderAsync();
bool spalteExistiert = false;
while (await reader.ReadAsync())
{
if (reader.GetString(1).Equals("Vorletzer Login", StringComparison.OrdinalIgnoreCase))
{
spalteExistiert = true;
break;
}
}
await reader.DisposeAsync();
if (!spalteExistiert)
{
var alterCmd = connection.CreateCommand();
alterCmd.CommandText = "ALTER TABLE Benutzer ADD COLUMN VorletzterLogin TEXT;";
await alterCmd.ExecuteNonQueryAsync();
Console.WriteLine("🛠 Spalte 'VorletzterLogin' wurde zur Tabelle 'Benutzer' hinzugefügt.");
}
else
{
Console.WriteLine("✅ Spalte 'VorletzterLogin' ist bereits vorhanden.");
}
}
public async Task UpdateStatusUndKommentarAsync(int id, bool erledigt, string mitarbeiterKommentar) public async Task UpdateStatusUndKommentarAsync(int id, bool erledigt, string mitarbeiterKommentar)
{ {
using var connection = new SqliteConnection($"Data Source={_dbPath}"); using var connection = new SqliteConnection($"Data Source={_dbPath}");

View File

@ -3,29 +3,60 @@
xmlns:model1="clr-namespace:ChronoFlow.Model;assembly=ChronoFlow.Model" xmlns:model1="clr-namespace:ChronoFlow.Model;assembly=ChronoFlow.Model"
x:Class="ChronoFlow.View.Admin.AlleProjekteView"> x:Class="ChronoFlow.View.Admin.AlleProjekteView">
<Grid RowDefinitions="Auto,Auto,*,Auto" Margin="20"> <Grid RowDefinitions="Auto,Auto,*,Auto" Margin="20">
<TextBlock Grid.Row="0" Text="Alle Projekte" FontSize="20" FontWeight="Bold" HorizontalAlignment="Center" Margin="0,0,0,10"/>
<TextBox Grid.Row="1" x:Name="Suchfeld" Watermark="🔍 Nach Projekt oder Mitarbeiter suchen..." KeyUp="Suchfeld_KeyUp" Margin="0,0,0,10"/> <!-- Überschrift -->
<TextBlock Grid.Row="0" Text="Alle Projekte" FontSize="20" FontWeight="Bold"
HorizontalAlignment="Center" Margin="0,0,0,10"/>
<!-- Suchfeld -->
<TextBox Grid.Row="1" x:Name="Suchfeld" Watermark="🔍 Nach Projekt oder Mitarbeiter suchen..."
KeyUp="Suchfeld_KeyUp" Margin="0,0,0,10"/>
<!-- Projektliste -->
<ScrollViewer Grid.Row="2"> <ScrollViewer Grid.Row="2">
<ListBox x:Name="ProjekteListe"> <ListBox x:Name="ProjekteListe">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type model1:Zeiteintrag}"> <DataTemplate DataType="{x:Type model1:Zeiteintrag}">
<StackPanel Orientation="Horizontal" Spacing="10" Margin="5"> <Border BorderBrush="Gray" BorderThickness="1" CornerRadius="5" Padding="10" Margin="0,5">
<TextBlock Text="{Binding Projekt}" Width="150"/> <StackPanel Spacing="5">
<TextBlock Text="{Binding Mitarbeiter}" Width="150"/>
<TextBlock Text="{Binding Startzeit}" Width="150"/> <!-- Projektübersicht -->
<TextBlock Text="{Binding Endzeit}" Width="150"/> <StackPanel Orientation="Horizontal" Spacing="10">
<TextBlock Text="{Binding Kommentar}" Width="200"/> <TextBlock Text="{Binding Projekt}" Width="150"/>
<Button Content="🖋 Bearbeiten" Tag="{Binding}" Click="Bearbeiten_Click"/> <TextBlock Text="{Binding Mitarbeiter}" Width="150"/>
<Button Content="🗑 Löschen" Tag="{Binding}" Click="Loeschen_Click"/> <TextBlock Text="{Binding Startzeit}" Width="150"/>
<Button Content="✅ Abschließen" Tag="{Binding}" Click="Abschliessen_Click"/> <TextBlock Text="{Binding Endzeit}" Width="150"/>
</StackPanel> </StackPanel>
<!-- Kommentar vom Admin -->
<TextBlock Text="📝 Kommentar (Admin):" FontSize="12" Foreground="LightGray"/>
<TextBlock Text="{Binding Kommentar}" FontWeight="SemiBold"/>
<!-- Kommentar vom Mitarbeiter -->
<TextBlock Text="💬 Kommentar (Mitarbeiter):" FontSize="12" Foreground="LightGray"/>
<TextBlock Text="{Binding MitarbeiterKommentar}"
FontStyle="Italic"
Foreground="Gray"
FontSize="12"
TextWrapping="Wrap"
Margin="0,2,0,0"/>
<!-- Aktionsbuttons -->
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Content="🖋 Bearbeiten" Tag="{Binding}" Click="Bearbeiten_Click"/>
<Button Content="🗑 Löschen" Tag="{Binding}" Click="Loeschen_Click"/>
<Button Content="✅ Abschließen" Tag="{Binding}" Click="Abschliessen_Click"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>
</ScrollViewer> </ScrollViewer>
<Button Grid.Row="3" Content="⬅ Zurück zum Dashboard" Click="ZurueckButton_Click" HorizontalAlignment="Center" Margin="0,10,0,0"/> <!-- Zurück-Button -->
<Button Grid.Row="3" Content="⬅ Zurück zum Dashboard"
Click="ZurueckButton_Click" HorizontalAlignment="Center" Margin="0,10,0,0"/>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -26,13 +26,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="MitarbeiterHinzufuegenView.axaml.cs"> <Compile Update="MitarbeiterHinzufuegenView.axaml.cs">
<DependentUpon>MitarbeiterHinzufuegenView.axaml</DependentUpon> <DependentUpon>MitarbeiterHinzufuegenView.axaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Update="Mitarbeiter\EmployeeTasksViewModel.axaml.cs">
<DependentUpon>EmployeeTasksViewModel.axaml.axaml</DependentUpon>
</Compile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -10,15 +10,17 @@ namespace ChronoFlow.View.Converter
public IBrush TrueBrush { get; set; } = Brushes.Blue; public IBrush TrueBrush { get; set; } = Brushes.Blue;
public IBrush FalseBrush { get; set; } = Brushes.Gray; public IBrush FalseBrush { get; set; } = Brushes.Gray;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
if (value is bool b) if (value is bool boolValue && boolValue)
return b ? TrueBrush : FalseBrush; return Brushes.Blue;
return FalseBrush; return Brushes.Gray;
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
throw new NotSupportedException(); {
throw new NotImplementedException(); // wird i.d.R. nicht benötigt
}
} }
} }

View File

@ -106,13 +106,20 @@ namespace ChronoFlow.View
try try
{ {
Console.WriteLine("🚀 Öffne MainWindow..."); Console.WriteLine("🚀 Öffne MainWindow...");
// ⏱️ bisherigen Login sichern und VorletzterLogin setzen
var bisherigerLogin = user.LetzterLogin;
user.LetzterLogin = DateTime.Now; user.LetzterLogin = DateTime.Now;
user.VorletzterLogin = bisherigerLogin;
// 💾 Neue Login-Zeitpunkte speichern
service.UpdateLoginZeiten(user);
// Fenster öffnen
var main = new MainWindow(user); var main = new MainWindow(user);
main.Show(); main.Show();
Console.WriteLine("✅ MainWindow wurde geöffnet."); main.Activate(); // ✨ explizit in den Vordergrund bringen
Close(); // LoginWindow erst danach schließen
this.Close();
Console.WriteLine("✅ LoginWindow wurde geschlossen.");
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -1,16 +1,12 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:ChronoFlow.ViewModels.Mitarbeiter"
xmlns:converter="clr-namespace:ChronoFlow.View.Converter"
x:Class="ChronoFlow.View.Mitarbeiter.EmployeeTasksView"> x:Class="ChronoFlow.View.Mitarbeiter.EmployeeTasksView">
<UserControl.Resources>
<converter:BoolToBrushConverter x:Key="BoolToBrushConverter"/>
</UserControl.Resources>
<ScrollViewer> <ScrollViewer>
<StackPanel Margin="20" Spacing="10"> <StackPanel Margin="20" Spacing="10">
<TextBlock Text="Meine Aufgaben" FontSize="24" FontWeight="Bold"/> <TextBlock Text="Meine Aufgaben" FontSize="24" FontWeight="Bold"/>
<!-- 🟢 Der Hinweis kommt vor dem ItemsControl --> <!-- Hinweis bei leerer Liste -->
<TextBlock Text="🎉 Du hast aktuell keine Aufgaben!" <TextBlock Text="🎉 Du hast aktuell keine Aufgaben!"
FontSize="16" FontSize="16"
FontStyle="Italic" FontStyle="Italic"
@ -18,16 +14,29 @@
HorizontalAlignment="Center" HorizontalAlignment="Center"
IsVisible="{Binding HatKeineEintraege}"/> IsVisible="{Binding HatKeineEintraege}"/>
<!-- 📝 Die eigentliche Aufgabenliste --> <!-- Aufgabenliste -->
<ItemsControl ItemsSource="{Binding Eintraege}"> <ItemsControl ItemsSource="{Binding Eintraege}">
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<Border BorderBrush="{Binding WurdeSeitLoginBearbeitet, Converter={StaticResource BoolToBrushConverter}}" <Border BorderBrush="{Binding WurdeSeitLoginBearbeitet, Converter={StaticResource BoolToBrushConverter}}"
BorderThickness="1" CornerRadius="4" Padding="10" Margin="5"> BorderThickness="1" CornerRadius="4" Padding="10" Margin="5">
<StackPanel Spacing="5"> <StackPanel Spacing="5">
<!-- Projekttitel -->
<TextBlock Text="{Binding Projekt}" FontWeight="Bold"/> <TextBlock Text="{Binding Projekt}" FontWeight="Bold"/>
<CheckBox Content="Erledigt" IsChecked="{Binding Erledigt}"/>
<!-- Admin-Kommentar -->
<TextBlock Text="📝 Kommentar (Admin):" FontSize="12" Foreground="LightGray"/>
<TextBlock Text="{Binding Kommentar}" FontWeight="SemiBold"/>
<!-- Mitarbeiter-Kommentar -->
<TextBlock Text="💬 Dein Kommentar:" FontSize="12" Foreground="LightGray"/>
<TextBox Text="{Binding MitarbeiterKommentar}" Watermark="Kommentar hinzufügen..."/> <TextBox Text="{Binding MitarbeiterKommentar}" Watermark="Kommentar hinzufügen..."/>
<!-- Erledigt-Checkbox -->
<CheckBox Content="Erledigt" IsChecked="{Binding Erledigt}"/>
<!-- Deadline -->
<TextBlock Text="{Binding Endzeit, StringFormat='Deadline: {0:dd.MM.yyyy}'}" <TextBlock Text="{Binding Endzeit, StringFormat='Deadline: {0:dd.MM.yyyy}'}"
Foreground="{Binding PrioritaetsFarbe}" Foreground="{Binding PrioritaetsFarbe}"
FontWeight="Bold" FontSize="14"/> FontWeight="Bold" FontSize="14"/>
@ -37,9 +46,9 @@
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>
<!-- Speichern -->
<Button Content="Änderungen speichern" Command="{Binding SpeichereEintraegeCommand}"/> <Button Content="Änderungen speichern" Command="{Binding SpeichereEintraegeCommand}"/>
<TextBlock Text="{Binding StatusText}" Foreground="Green" FontStyle="Italic"/> <TextBlock Text="{Binding StatusText}" Foreground="Green" FontStyle="Italic"/>
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>

View File

@ -1,5 +1,5 @@
using Avalonia.Controls; using Avalonia.Controls;
using ChronoFlow.ViewModels.Mitarbeiter; using ChronoFlow.View.Mitarbeiter;
using ChronoFlow.Persistence; using ChronoFlow.Persistence;
using ChronoFlow.Model; using ChronoFlow.Model;

View File

@ -1,33 +0,0 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodels="clr-namespace:ChronoFlow.ViewModels"
mc:Ignorable="d">
<StackPanel Margin="20" Spacing="10">
<TextBlock Text="Meine Aufgaben" FontSize="24" FontWeight="Bold"/>
<ItemsControl ItemsSource="{Binding Eintraege}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Gray" Padding="10" Margin="5">
<StackPanel Spacing="5">
<TextBlock Text="{Binding TaskDescription}" FontWeight="Bold"/>
<TextBlock Text="{Binding Date}" FontStyle="Italic"/>
<TextBlock Text="Priorität: {Binding Priority}" Foreground="DarkRed"/>
<CheckBox Content="Erledigt" IsChecked="{Binding IsCompleted}"/>
<TextBox Text="{Binding Comment}" Watermark="Kommentar eingeben..."/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Änderungen speichern" Command="{Binding SaveChangesCommand}" HorizontalAlignment="Right"/>
<TextBlock Text="{Binding StatusText}"
Foreground="Green"
FontStyle="Italic"
FontWeight="SemiBold"
Margin="5"/>
</StackPanel>
</UserControl>

View File

@ -1,3 +1,4 @@
// TestKommentar
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
@ -6,28 +7,49 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using ChronoFlow.Model; using ChronoFlow.Model;
using ChronoFlow.Persistence; using ChronoFlow.Persistence;
using ChronoFlow.View.Mitarbeiter;
namespace ChronoFlow.ViewModels.Mitarbeiter namespace ChronoFlow.View.Mitarbeiter
{ {
/// <summary>
/// ViewModel für die Mitarbeiter-Aufgabenansicht.
/// Enthält alle Aufgaben für den eingeloggten Benutzer und erlaubt das Speichern von Änderungen.
/// </summary>
public partial class EmployeeTasksViewModel : ObservableObject public partial class EmployeeTasksViewModel : ObservableObject
{ {
// 🧑‍💼 Der aktuell eingeloggte Benutzer (Mitarbeiter)
private readonly User _benutzer; private readonly User _benutzer;
// 💾 Zugriff auf die Datenbank-Funktionen (SQL-Repository)
private readonly IZeiterfassungsRepository _repository; private readonly IZeiterfassungsRepository _repository;
// 📛 Einfacher Zugriff auf den Benutzernamen (spart Schreibarbeit)
private readonly string aktuellerBenutzername; private readonly string aktuellerBenutzername;
// 📋 Alle Zeiteinträge, die dem Benutzer angezeigt werden
[ObservableProperty] [ObservableProperty]
private ObservableCollection<Zeiteintrag> eintraege = new(); private ObservableCollection<Zeiteintrag> eintraege = new();
// 💬 Statusmeldung unten im Fenster (z.B. bei Erfolg)
[ObservableProperty] [ObservableProperty]
private string? statusText; private string? statusText;
// ✅ Hilfs-Property, die sagt: "Gibt es keine Einträge?"
public bool HatKeineEintraege => Eintraege.Count == 0; public bool HatKeineEintraege => Eintraege.Count == 0;
/// <summary>
/// Diese Methode wird automatisch aufgerufen, wenn sich die Einträge ändern.
/// Damit wird die UI über die Änderung von 'HatKeineEintraege' informiert.
/// </summary>
partial void OnEintraegeChanged(ObservableCollection<Zeiteintrag>? oldValue, ObservableCollection<Zeiteintrag> newValue) partial void OnEintraegeChanged(ObservableCollection<Zeiteintrag>? oldValue, ObservableCollection<Zeiteintrag> newValue)
{ {
OnPropertyChanged(nameof(HatKeineEintraege)); OnPropertyChanged(nameof(HatKeineEintraege));
} }
/// <summary>
/// Konstruktor: Bekommt den eingeloggten Benutzer und das Repository.
/// Lädt automatisch alle offenen Einträge für diesen Benutzer.
/// </summary>
public EmployeeTasksViewModel(User benutzer, IZeiterfassungsRepository repository) public EmployeeTasksViewModel(User benutzer, IZeiterfassungsRepository repository)
{ {
_benutzer = benutzer; _benutzer = benutzer;
@ -36,9 +58,15 @@ namespace ChronoFlow.ViewModels.Mitarbeiter
Console.WriteLine($"[DEBUG] ViewModel erstellt für Benutzer: {aktuellerBenutzername}"); Console.WriteLine($"[DEBUG] ViewModel erstellt für Benutzer: {aktuellerBenutzername}");
_ = LadeEintraegeAsync(); // Lade Daten automatisch beim Öffnen // Daten automatisch beim Öffnen laden
_ = LadeEintraegeAsync();
} }
/// <summary>
/// Lädt alle offenen Einträge für den aktuell eingeloggten Mitarbeiter.
/// Sortiert nach Fälligkeitsdatum (Endzeit).
/// Erkennt auch, ob seit dem letzten Login Änderungen gemacht wurden.
/// </summary>
[RelayCommand] [RelayCommand]
public async Task LadeEintraegeAsync() public async Task LadeEintraegeAsync()
{ {
@ -49,23 +77,25 @@ namespace ChronoFlow.ViewModels.Mitarbeiter
.OrderBy(e => e.Endzeit) .OrderBy(e => e.Endzeit)
.ToList(); .ToList();
// 🔔 Setze Markierung für geänderte Aufgaben // 🔔 Markiere geänderte Einträge seit dem letzten Login
foreach (var eintrag in offene) foreach (var eintrag in offene)
{ {
eintrag.WurdeSeitLoginBearbeitet = eintrag.LetzteBearbeitung > _benutzer.LetzterLogin; eintrag.WurdeSeitLoginBearbeitet = eintrag.LetzteBearbeitung > _benutzer.VorletzterLogin;
// 🔍 Debug-Ausgabe zur Prüfung
Console.WriteLine($"[DEBUG] Eintrag {eintrag.Id}: Endzeit={eintrag.Endzeit}, LetzteBearbeitung={eintrag.LetzteBearbeitung}, LetzterLogin={_benutzer.LetzterLogin}, Markiert={eintrag.WurdeSeitLoginBearbeitet}");
} }
// 🔔 Zeige Hinweis, wenn neue Änderungen vorhanden sind
if (offene.Any(e => e.WurdeSeitLoginBearbeitet)) if (offene.Any(e => e.WurdeSeitLoginBearbeitet))
StatusText = "📢 Es wurden Aufgaben seit Ihrem letzten Login geändert."; StatusText = "📢 Es wurden Aufgaben seit Ihrem letzten Login geändert.";
// 🔄 Aktualisiere ObservableCollection für UI
Eintraege = new ObservableCollection<Zeiteintrag>(offene); Eintraege = new ObservableCollection<Zeiteintrag>(offene);
} }
/// <summary>
/// Speichert alle Änderungen an den sichtbaren Einträgen
/// (Status 'erledigt' + Mitarbeiter-Kommentar).
/// Danach wird die Liste automatisch neu geladen.
/// </summary>
[RelayCommand] [RelayCommand]
public async Task SpeichereEintraegeAsync() public async Task SpeichereEintraegeAsync()
{ {
@ -79,7 +109,9 @@ namespace ChronoFlow.ViewModels.Mitarbeiter
} }
StatusText = "✅ Änderungen gespeichert."; StatusText = "✅ Änderungen gespeichert.";
await LadeEintraegeAsync(); // automatisch neu laden
// 🔄 Nach dem Speichern direkt neu laden
await LadeEintraegeAsync();
} }
} }
} }