last changes

This commit is contained in:
ViperioN1339 2025-06-21 11:32:41 +02:00
parent 8ca1fb91dd
commit b617d39c8f
19 changed files with 236 additions and 144 deletions

View File

@ -6,6 +6,7 @@
<entry key="ChronoFlow.View/Admin/AdminMainView.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" /> <entry key="ChronoFlow.View/Admin/AdminMainView.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" />
<entry key="ChronoFlow.View/Admin/ConfirmDialog.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" /> <entry key="ChronoFlow.View/Admin/ConfirmDialog.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" />
<entry key="ChronoFlow.View/Admin/MitarbeiterListeView.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" /> <entry key="ChronoFlow.View/Admin/MitarbeiterListeView.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" />
<entry key="ChronoFlow.View/Admin/ProjektErstellenView.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" />
<entry key="ChronoFlow.View/App.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" /> <entry key="ChronoFlow.View/App.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" />
<entry key="ChronoFlow.View/LoginView.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" /> <entry key="ChronoFlow.View/LoginView.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" />
<entry key="ChronoFlow.View/LoginWindow.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" /> <entry key="ChronoFlow.View/LoginWindow.axaml" value="ChronoFlow.View/ChronoFlow.View.csproj" />

View File

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

View File

@ -37,5 +37,8 @@ namespace ChronoFlow.Model
return "Green"; return "Green";
} }
} }
public DateTime LetzteBearbeitung { get; set; }
public bool IstNeu { get; set; } // wird im ViewModel gesetzt
public bool WurdeSeitLoginBearbeitet { get; set; }
} }
} }

View File

@ -92,6 +92,7 @@ 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, "Zeiteintraege", "LetzteBearbeitung", "TEXT");
} }
private void AddColumnIfMissing(SqliteConnection connection, string tableName, string columnName, string columnType) private void AddColumnIfMissing(SqliteConnection connection, string tableName, string columnName, string columnType)
@ -247,9 +248,10 @@ namespace ChronoFlow.Persistence
var cmd = connection.CreateCommand(); var cmd = connection.CreateCommand();
cmd.CommandText = @" cmd.CommandText = @"
INSERT INTO Zeiteintraege INSERT INTO Zeiteintraege
(Mitarbeiter, Startzeit, Endzeit, Projekt, Kommentar, Erledigt, MitarbeiterKommentar) (Mitarbeiter, Startzeit, Endzeit, Projekt, Kommentar, Erledigt, MitarbeiterKommentar, LetzteBearbeitung)
VALUES ($Mitarbeiter, $Startzeit, $Endzeit, $Projekt, $Kommentar, $Erledigt, $MitarbeiterKommentar); VALUES
"; ($Mitarbeiter, $Startzeit, $Endzeit, $Projekt, $Kommentar, $Erledigt, $MitarbeiterKommentar, $LetzteBearbeitung);";
cmd.Parameters.AddWithValue("$Mitarbeiter", eintrag.Mitarbeiter); cmd.Parameters.AddWithValue("$Mitarbeiter", eintrag.Mitarbeiter);
cmd.Parameters.AddWithValue("$Startzeit", eintrag.Startzeit.ToString("o")); cmd.Parameters.AddWithValue("$Startzeit", eintrag.Startzeit.ToString("o"));
@ -258,6 +260,7 @@ namespace ChronoFlow.Persistence
cmd.Parameters.AddWithValue("$Kommentar", eintrag.Kommentar ?? ""); cmd.Parameters.AddWithValue("$Kommentar", eintrag.Kommentar ?? "");
cmd.Parameters.AddWithValue("$Erledigt", eintrag.Erledigt ? 1 : 0); cmd.Parameters.AddWithValue("$Erledigt", eintrag.Erledigt ? 1 : 0);
cmd.Parameters.AddWithValue("$MitarbeiterKommentar", eintrag.MitarbeiterKommentar ?? ""); cmd.Parameters.AddWithValue("$MitarbeiterKommentar", eintrag.MitarbeiterKommentar ?? "");
cmd.Parameters.AddWithValue("$LetzteBearbeitung", DateTime.Now.ToString("o"));
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
@ -302,13 +305,13 @@ namespace ChronoFlow.Persistence
cmd.CommandText = @" cmd.CommandText = @"
UPDATE Zeiteintraege UPDATE Zeiteintraege
SET Projekt = $Projekt, SET Projekt = $Projekt,
Kommentar = $Kommentar, Kommentar = $Kommentar,
Startzeit = $Startzeit, Startzeit = $Startzeit,
Endzeit = $Endzeit, Endzeit = $Endzeit,
Mitarbeiter = $Mitarbeiter, Mitarbeiter = $Mitarbeiter,
Erledigt = $Erledigt Erledigt = $Erledigt,
WHERE Id = $Id; LetzteBearbeitung = $LetzteBearbeitung
"; WHERE Id = $Id;";
cmd.Parameters.AddWithValue("$Projekt", projekt.Projekt); cmd.Parameters.AddWithValue("$Projekt", projekt.Projekt);
cmd.Parameters.AddWithValue("$Kommentar", projekt.Kommentar ?? ""); cmd.Parameters.AddWithValue("$Kommentar", projekt.Kommentar ?? "");
@ -317,6 +320,7 @@ namespace ChronoFlow.Persistence
cmd.Parameters.AddWithValue("$Mitarbeiter", projekt.Mitarbeiter); cmd.Parameters.AddWithValue("$Mitarbeiter", projekt.Mitarbeiter);
cmd.Parameters.AddWithValue("$Erledigt", projekt.Erledigt ? 1 : 0); cmd.Parameters.AddWithValue("$Erledigt", projekt.Erledigt ? 1 : 0);
cmd.Parameters.AddWithValue("$Id", projekt.Id); cmd.Parameters.AddWithValue("$Id", projekt.Id);
cmd.Parameters.AddWithValue("$LetzteBearbeitung", DateTime.Now.ToString("o"));
int rowsAffected = cmd.ExecuteNonQuery(); int rowsAffected = cmd.ExecuteNonQuery();
Console.WriteLine($"✏ Projekt aktualisiert (Id={projekt.Id}, Rows affected: {rowsAffected})"); Console.WriteLine($"✏ Projekt aktualisiert (Id={projekt.Id}, Rows affected: {rowsAffected})");
@ -464,34 +468,39 @@ namespace ChronoFlow.Persistence
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 async Task<List<Zeiteintrag>> GetEintraegeFuerMitarbeiterAsync(string mitarbeiterName) public async Task<List<Zeiteintrag>> GetEintraegeFuerMitarbeiterAsync(string name)
{ {
var eintraege = new List<Zeiteintrag>(); var eintraege = new List<Zeiteintrag>();
using var connection = new SqliteConnection($"Data Source={_dbPath}"); using var connection = new SqliteConnection($"Data Source={_dbPath}");
await connection.OpenAsync(); await connection.OpenAsync();
var cmd = connection.CreateCommand(); var cmd = connection.CreateCommand();
cmd.CommandText = @" cmd.CommandText = @"
SELECT * FROM Zeiteintraege SELECT Id, Mitarbeiter, Startzeit, Endzeit, Projekt, Kommentar, Erledigt, MitarbeiterKommentar, LetzteBearbeitung
WHERE Mitarbeiter = $Mitarbeiter; FROM Zeiteintraege
"; WHERE Mitarbeiter = $Name;
cmd.Parameters.AddWithValue("$Mitarbeiter", mitarbeiterName); ";
cmd.Parameters.AddWithValue("$Name", name);
using var reader = await cmd.ExecuteReaderAsync(); using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync()) while (await reader.ReadAsync())
{ {
eintraege.Add(new Zeiteintrag eintraege.Add(new Zeiteintrag
{ {
Id = reader.GetInt32(0), Id = reader.GetInt32(0),
Mitarbeiter = reader.GetString(1), Mitarbeiter = reader.GetString(1),
Startzeit = DateTime.Parse(reader.GetString(2)), Startzeit = reader.GetDateTime(2),
Endzeit = DateTime.Parse(reader.GetString(3)), Endzeit = reader.GetDateTime(3),
Projekt = reader.GetString(4), Projekt = reader.GetString(4),
Kommentar = reader.GetString(5), Kommentar = reader.GetString(5),
Erledigt = Convert.ToInt32(reader["Erledigt"]) == 1, Erledigt = reader.GetBoolean(6),
MitarbeiterKommentar = reader.GetString(7) MitarbeiterKommentar = reader.GetString(7),
LetzteBearbeitung = reader.IsDBNull(8) ? DateTime.MinValue : reader.GetDateTime(8)
}); });
} }
return eintraege; return eintraege;
} }
@ -502,19 +511,22 @@ namespace ChronoFlow.Persistence
var cmd = connection.CreateCommand(); var cmd = connection.CreateCommand();
cmd.CommandText = @" cmd.CommandText = @"
UPDATE Zeiteintraege UPDATE Zeiteintraege
SET Erledigt = $Erledigt, SET Erledigt = $Erledigt,
MitarbeiterKommentar = $Kommentar MitarbeiterKommentar = $Kommentar,
WHERE Id = $Id; LetzteBearbeitung = $Bearbeitet
"; WHERE Id = $Id;
";
cmd.Parameters.AddWithValue("$Erledigt", erledigt ? 1 : 0); cmd.Parameters.AddWithValue("$Erledigt", erledigt ? 1 : 0);
cmd.Parameters.AddWithValue("$Kommentar", mitarbeiterKommentar ?? ""); cmd.Parameters.AddWithValue("$Kommentar", mitarbeiterKommentar ?? "");
cmd.Parameters.AddWithValue("$Bearbeitet", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
cmd.Parameters.AddWithValue("$Id", id); cmd.Parameters.AddWithValue("$Id", id);
int rowsAffected = await cmd.ExecuteNonQueryAsync(); int rowsAffected = await cmd.ExecuteNonQueryAsync();
Console.WriteLine($"✏ Zeiteintrag (Id={id}) aktualisiert: erledigt={erledigt}, kommentar gesetzt."); Console.WriteLine($"✏ Zeiteintrag (Id={id}) aktualisiert: erledigt={erledigt}, LetzteBearbeitung gesetzt.");
} }
} }
} }

View File

@ -3,57 +3,37 @@
xmlns:model="clr-namespace:ChronoFlow.Model;assembly=ChronoFlow.Model" xmlns:model="clr-namespace:ChronoFlow.Model;assembly=ChronoFlow.Model"
x:Class="ChronoFlow.View.Admin.AdminMainView"> x:Class="ChronoFlow.View.Admin.AdminMainView">
<SplitView x:Name="AdminPane" DisplayMode="CompactInline" IsPaneOpen="True" CompactPaneLength="37" OpenPaneLength="200"> <DockPanel>
<!-- 🧭 Top-Menüleiste für Admins -->
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Background="Black" Margin="5" Spacing="10">
<Button Content="📋 Alle bestehenden Projekte" Click="AlleProjekte_Click"/>
<Button Content="👥 Mitarbeiterliste" Click="MitarbeiterListe_Click"/>
<Button Content="✅ Abgeschlossene Projekte" Click="AbgeschlosseneProjekte_Click"/>
<Button Content=" Mitarbeiter hinzufügen" Click="MitarbeiterHinzufuegen_Click"/>
<Button Content=" Projekt erstellen" Click="ProjektErstellen_Click"/>
<!-- Linke Sidebar (SplitView-Pane) --> </StackPanel>
<SplitView.Pane>
<StackPanel>
<!-- Burger-Button -->
<Button Content="☰" Click="TogglePane_Click"/>
<!-- Navigation Buttons --> <!-- Hauptinhalt -->
<Button Content="🏠 Dashboard" Click="Dashboard_Click"/> <StackPanel Margin="20" Spacing="15">
<Button Content="📋 Alle Projekte anzeigen" Click="AlleProjekte_Click"/> <TextBlock Text="Admin-Dashboard" FontSize="24" FontWeight="Bold" HorizontalAlignment="Center"/>
<Button Content="👥 Mitarbeiter-Liste" Click="MitarbeiterListe_Click"/>
<Button Content="✅ Abgeschlossene Projekte" Click="AbgeschlosseneProjekte_Click" />
<Button Content="⚙ Einstellungen" Click="Einstellungen_Click"/>
</StackPanel>
</SplitView.Pane>
<!-- Hauptinhalt --> <TextBlock Text="Zuletzt hinzugefügte Projekte" FontSize="18" FontWeight="SemiBold" Margin="0,20,0,10"/>
<SplitView.Content>
<StackPanel Margin="20" Spacing="15">
<!-- Überschrift --> <ItemsControl x:Name="LetzteProjekteListe">
<TextBlock Text="Admin-Dashboard" FontSize="24" FontWeight="Bold" HorizontalAlignment="Center"/> <ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type model:Zeiteintrag}">
<!-- Aktions-Buttons (oben) --> <Border BorderBrush="Gray" BorderThickness="1" Padding="10" Margin="0,5">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Spacing="10"> <StackPanel>
<Button Content=" Mitarbeiter hinzufügen" Width="200" Height="50" Click="MitarbeiterHinzufuegen_Click"/> <TextBlock Text="{Binding Projekt}" FontWeight="Bold"/>
<Button Content=" Projekt erstellen" Width="200" Height="50" Click="ProjektErstellen_Click"/> <TextBlock Text="{Binding Mitarbeiter}"/>
</StackPanel> <TextBlock Text="{Binding Startzeit, StringFormat='Start: {0:G}'}"/>
<TextBlock Text="{Binding Endzeit, StringFormat='Ende: {0:G}'}"/>
<!-- Anzeige der letzten Projekte --> </StackPanel>
<TextBlock Text="Zuletzt hinzugefügte Projekte" FontSize="18" FontWeight="SemiBold" Margin="0,20,0,10"/> </Border>
</DataTemplate>
<ItemsControl x:Name="LetzteProjekteListe"> </ItemsControl.ItemTemplate>
<ItemsControl.ItemTemplate> </ItemsControl>
<DataTemplate DataType="{x:Type model:Zeiteintrag}"> </StackPanel>
<Border BorderBrush="Gray" BorderThickness="1" Padding="10" Margin="0,5"> </DockPanel>
<StackPanel>
<TextBlock Text="{Binding Projekt}" FontWeight="Bold"/>
<TextBlock Text="{Binding Mitarbeiter}"/>
<TextBlock Text="{Binding Startzeit, StringFormat='Start: {0:G}'}"/>
<TextBlock Text="{Binding Endzeit, StringFormat='Ende: {0:G}'}"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</SplitView.Content>
</SplitView>
</UserControl> </UserControl>

View File

@ -67,12 +67,6 @@ namespace ChronoFlow.View.Admin
{ {
_viewManager.Show("ProjektErstellen"); _viewManager.Show("ProjektErstellen");
} }
private void Dashboard_Click(object sender, RoutedEventArgs e)
{
_viewManager.Show("AdminMain");
}
private void AlleProjekte_Click(object sender, RoutedEventArgs e) private void AlleProjekte_Click(object sender, RoutedEventArgs e)
{ {
_viewManager.Show("AlleProjekte"); _viewManager.Show("AlleProjekte");
@ -83,15 +77,9 @@ namespace ChronoFlow.View.Admin
_viewManager.Show("MitarbeiterListe"); _viewManager.Show("MitarbeiterListe");
} }
private void Einstellungen_Click(object sender, RoutedEventArgs e)
{
_viewManager.Show("Einstellungen");
}
private void TogglePane_Click(object sender, RoutedEventArgs e)
{
AdminPane.IsPaneOpen = !AdminPane.IsPaneOpen;
}
public void AktualisiereLetzteProjekte() public void AktualisiereLetzteProjekte()
{ {
@ -102,5 +90,7 @@ namespace ChronoFlow.View.Admin
{ {
_viewManager.Show("AbgeschlosseneProjekte"); _viewManager.Show("AbgeschlosseneProjekte");
} }
} }
} }

View File

@ -3,8 +3,8 @@
x:Class="ChronoFlow.View.Admin.MitarbeiterBearbeitenDialog" x:Class="ChronoFlow.View.Admin.MitarbeiterBearbeitenDialog"
Width="450" Height="600" Width="450" Height="600"
Title="Mitarbeiter bearbeiten"> Title="Mitarbeiter bearbeiten">
<ScrollViewer>
<StackPanel Margin="20" Spacing="10"> <StackPanel Margin="20" Spacing="15">
<TextBlock Text="Username:" /> <TextBlock Text="Username:" />
<TextBox x:Name="UsernameBox" /> <TextBox x:Name="UsernameBox" />
@ -28,4 +28,5 @@
IsVisible="False" IsVisible="False"
Margin="0,10,0,0" /> Margin="0,10,0,0" />
</StackPanel> </StackPanel>
</ScrollViewer>
</Window> </Window>

View File

@ -4,7 +4,8 @@
Width="500" Height="600" Width="500" Height="600"
Title="Projekt bearbeiten"> Title="Projekt bearbeiten">
<StackPanel Margin="20" Spacing="12"> <ScrollViewer>
<StackPanel Margin="20" Spacing="15">
<TextBlock Text="Projektname:" /> <TextBlock Text="Projektname:" />
<TextBox x:Name="ProjektnameBox" /> <TextBox x:Name="ProjektnameBox" />
@ -25,4 +26,5 @@
<Button Content="❌ Abbrechen" Width="130" Click="AbbrechenButton_Click" /> <Button Content="❌ Abbrechen" Width="130" Click="AbbrechenButton_Click" />
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
</ScrollViewer>
</Window> </Window>

View File

@ -2,7 +2,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ChronoFlow.View.Admin.ProjektErstellenView"> x:Class="ChronoFlow.View.Admin.ProjektErstellenView">
<StackPanel Margin="20" Spacing="10"> <ScrollViewer>
<StackPanel Margin="20" Spacing="15">
<TextBlock Text="Neues Projekt erstellen" FontSize="20" FontWeight="Bold" HorizontalAlignment="Center" /> <TextBlock Text="Neues Projekt erstellen" FontSize="20" FontWeight="Bold" HorizontalAlignment="Center" />
@ -29,11 +30,12 @@
<StackPanel Orientation="Horizontal" Spacing="10" HorizontalAlignment="Center" Margin="0,10,0,0"> <StackPanel Orientation="Horizontal" Spacing="10" HorizontalAlignment="Center" Margin="0,10,0,0">
<Button Content="✅ Speichern" Click="SpeichernButton_Click" Width="115" /> <Button Content="✅ Speichern" Click="SpeichernButton_Click" Width="115" />
<Button Content="⬅ Zurück zum Dashboard" Click="ZurueckButton_Click" Width="150" /> <Button Content="⬅ Zurück zum Dashboard" Click="ZurueckButton_Click" Width="180" />
</StackPanel> </StackPanel>
<TextBlock x:Name="FeedbackText" Foreground="Red" IsVisible="False" /> <TextBlock x:Name="FeedbackText" Foreground="Red" IsVisible="False" />
</StackPanel> </StackPanel>
</ScrollViewer>
</UserControl> </UserControl>

View File

@ -1,8 +1,15 @@
<Application xmlns="https://github.com/avaloniaui" <Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:themes="clr-namespace:Avalonia.Themes.Fluent;assembly=Avalonia.Themes.Fluent" xmlns:themes="clr-namespace:Avalonia.Themes.Fluent;assembly=Avalonia.Themes.Fluent"
x:Class="ChronoFlow.App" xmlns:conv="clr-namespace:ChronoFlow.View.Converter"
RequestedThemeVariant="Default"> x:Class="ChronoFlow.App">
<Application.Resources>
<conv:BoolToBrushConverter x:Key="BoolToBrushConverter"
TrueBrush="Blue"
FalseBrush="Gray"/>
</Application.Resources>
<Application.Styles> <Application.Styles>
<themes:FluentTheme /> <themes:FluentTheme />
</Application.Styles> </Application.Styles>

View File

@ -13,6 +13,9 @@
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="MessageBox.Avalonia" Version="0.10.4" /> <PackageReference Include="MessageBox.Avalonia" Version="0.10.4" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.6" /> <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.6" />
<PackageReference Include="ReactiveUI" Version="20.3.1" />
<PackageReference Include="System.Reactive" Version="6.0.1" />
<PackageReference Include="WCKY.Avalonia.AnimationLibrary" Version="1.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -0,0 +1,24 @@
using System;
using System.Globalization;
using Avalonia.Data.Converters;
using Avalonia.Media;
namespace ChronoFlow.View.Converter
{
public class BoolToBrushConverter : IValueConverter
{
public IBrush TrueBrush { get; set; } = Brushes.Blue;
public IBrush FalseBrush { get; set; } = Brushes.Gray;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool b)
return b ? TrueBrush : FalseBrush;
return FalseBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
throw new NotSupportedException();
}
}

View File

@ -106,6 +106,7 @@ namespace ChronoFlow.View
try try
{ {
Console.WriteLine("🚀 Öffne MainWindow..."); Console.WriteLine("🚀 Öffne MainWindow...");
user.LetzterLogin = DateTime.Now;
var main = new MainWindow(user); var main = new MainWindow(user);
main.Show(); main.Show();
Console.WriteLine("✅ MainWindow wurde geöffnet."); Console.WriteLine("✅ MainWindow wurde geöffnet.");
@ -120,5 +121,6 @@ namespace ChronoFlow.View
ErrorText.IsVisible = true; ErrorText.IsVisible = true;
} }
} }
} }
} }

View File

@ -5,9 +5,18 @@
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="600" mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="600"
x:Class="ChronoFlow.View.MainWindow" x:Class="ChronoFlow.View.MainWindow"
Title="ChronoFlow"> Title="ChronoFlow">
<DockPanel LastChildFill="True">
<Button Content="🔓 Logout"
HorizontalAlignment="Right"
Margin="5"
Padding="8,4"
Click="Logout_Click"
DockPanel.Dock="Top"
Background="Transparent"
BorderBrush="Gray"/>
<Grid> <Grid>
<ContentControl x:Name="ContentArea" /> <ContentControl x:Name="ContentArea" />
</Grid> </Grid>
</DockPanel>
</Window> </Window>

View File

@ -2,6 +2,7 @@ using System;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using ChronoFlow.Model; using ChronoFlow.Model;
using ChronoFlow.Persistence;
using ChronoFlow.View.Admin; using ChronoFlow.View.Admin;
using ChronoFlow.View.Mitarbeiter; using ChronoFlow.View.Mitarbeiter;
@ -27,7 +28,8 @@ namespace ChronoFlow.View
_viewManager.Register("AlleProjekte", () => new AlleProjekteView(_viewManager)); _viewManager.Register("AlleProjekte", () => new AlleProjekteView(_viewManager));
_viewManager.Register("MitarbeiterListe", () => new MitarbeiterListeView(_viewManager)); _viewManager.Register("MitarbeiterListe", () => new MitarbeiterListeView(_viewManager));
_viewManager.Register("AbgeschlosseneProjekte", () => new AbgeschlosseneProjekteView(_viewManager)); _viewManager.Register("AbgeschlosseneProjekte", () => new AbgeschlosseneProjekteView(_viewManager));
_viewManager.Register("Zeiterfassung", () => new EmployeeTasksView(_loggedInUser.Username)); _viewManager.Register("Zeiterfassung", () =>
new EmployeeTasksView(_loggedInUser, new SqliteZeiterfassungsService()));
if (_loggedInUser.Role == "Admin") if (_loggedInUser.Role == "Admin")
{ {
@ -60,5 +62,12 @@ namespace ChronoFlow.View
{ {
_viewManager.Show("AdminMain"); _viewManager.Show("AdminMain");
} }
private void Logout_Click(object? sender, RoutedEventArgs e)
{
var loginWindow = new LoginWindow();
loginWindow.Show();
this.Close(); // Aktuelles Fenster schließen
}
} }
} }

View File

@ -1,28 +1,45 @@
<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: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">
<StackPanel Margin="20" Spacing="10"> <UserControl.Resources>
<TextBlock Text="Meine Aufgaben" FontSize="24" FontWeight="Bold"/> <converter:BoolToBrushConverter x:Key="BoolToBrushConverter"/>
</UserControl.Resources>
<ScrollViewer>
<StackPanel Margin="20" Spacing="10">
<TextBlock Text="Meine Aufgaben" FontSize="24" FontWeight="Bold"/>
<ItemsControl ItemsSource="{Binding Eintraege}"> <!-- 🟢 Der Hinweis kommt vor dem ItemsControl -->
<ItemsControl.ItemTemplate> <TextBlock Text="🎉 Du hast aktuell keine Aufgaben!"
<DataTemplate> FontSize="16"
<Border BorderThickness="1" BorderBrush="Gray" CornerRadius="4" Padding="10" Margin="5"> FontStyle="Italic"
<StackPanel Spacing="5"> FontWeight="Medium"
<TextBlock Text="{Binding Projekt}" FontWeight="Bold"/> HorizontalAlignment="Center"
<CheckBox Content="Erledigt" IsChecked="{Binding Erledigt}"/> IsVisible="{Binding HatKeineEintraege}"/>
<TextBox Text="{Binding MitarbeiterKommentar}" Watermark="Kommentar hinzufügen..."/>
<TextBlock Text="{Binding Endzeit, StringFormat='Deadline: {0:dd.MM.yyyy}'}" <!-- 📝 Die eigentliche Aufgabenliste -->
Foreground="{Binding PrioritaetsFarbe}" <ItemsControl ItemsSource="{Binding Eintraege}">
FontWeight="Bold" FontSize="14"/> <ItemsControl.ItemTemplate>
</StackPanel> <DataTemplate>
</Border> <Border BorderBrush="{Binding WurdeSeitLoginBearbeitet, Converter={StaticResource BoolToBrushConverter}}"
</DataTemplate> BorderThickness="1" CornerRadius="4" Padding="10" Margin="5">
</ItemsControl.ItemTemplate> <StackPanel Spacing="5">
</ItemsControl> <TextBlock Text="{Binding Projekt}" FontWeight="Bold"/>
<CheckBox Content="Erledigt" IsChecked="{Binding Erledigt}"/>
<TextBox Text="{Binding MitarbeiterKommentar}" Watermark="Kommentar hinzufügen..."/>
<TextBlock Text="{Binding Endzeit, StringFormat='Deadline: {0:dd.MM.yyyy}'}"
Foreground="{Binding PrioritaetsFarbe}"
FontWeight="Bold" FontSize="14"/>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Button Content="Änderungen speichern" Command="{Binding SpeichereEintraegeCommand}"/>
<TextBlock Text="{Binding StatusText}" Foreground="Green" FontStyle="Italic"/>
</StackPanel>
</ScrollViewer>
<Button Content="Änderungen speichern" Command="{Binding SpeichereEintraegeCommand}"/>
<TextBlock Text="{Binding StatusText}" Foreground="Green" FontStyle="Italic"/>
</StackPanel>
</UserControl> </UserControl>

View File

@ -1,20 +1,16 @@
using Avalonia.Controls; using Avalonia.Controls;
using ChronoFlow.ViewModels.Mitarbeiter; using ChronoFlow.ViewModels.Mitarbeiter;
using ChronoFlow.Persistence; using ChronoFlow.Persistence;
using ChronoFlow.Model;
namespace ChronoFlow.View.Mitarbeiter namespace ChronoFlow.View.Mitarbeiter
{ {
public partial class EmployeeTasksView : UserControl public partial class EmployeeTasksView : UserControl
{ {
public EmployeeTasksView(string benutzername) public EmployeeTasksView(User user, IZeiterfassungsRepository repository)
{ {
InitializeComponent(); InitializeComponent();
DataContext = new EmployeeTasksViewModel(user, repository);
// Benutzername dynamisch übergeben
DataContext = new EmployeeTasksViewModel(
new SqliteZeiterfassungsService(),
benutzername
);
} }
} }
} }

View File

@ -1,4 +1,6 @@
using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
@ -9,46 +11,75 @@ namespace ChronoFlow.ViewModels.Mitarbeiter
{ {
public partial class EmployeeTasksViewModel : ObservableObject public partial class EmployeeTasksViewModel : ObservableObject
{ {
// Liste aller Zeiteinträge für den aktuell eingeloggten Mitarbeiter private readonly User _benutzer;
private readonly IZeiterfassungsRepository _repository;
private readonly string aktuellerBenutzername;
[ObservableProperty] [ObservableProperty]
private ObservableCollection<Zeiteintrag> eintraege = new(); private ObservableCollection<Zeiteintrag> eintraege = new();
// Ausgabe für Erfolg/Nachricht
[ObservableProperty] [ObservableProperty]
private string? statusText; private string? statusText;
private readonly IZeiterfassungsRepository repository; public bool HatKeineEintraege => Eintraege.Count == 0;
private readonly string aktuellerBenutzername;
// Konstruktor erhält Repository (z.B. SqliteZeiterfassungsService) + aktuellen Benutzernamen partial void OnEintraegeChanged(ObservableCollection<Zeiteintrag>? oldValue, ObservableCollection<Zeiteintrag> newValue)
public EmployeeTasksViewModel(IZeiterfassungsRepository repository, string aktuellerBenutzername)
{ {
this.repository = repository; OnPropertyChanged(nameof(HatKeineEintraege));
this.aktuellerBenutzername = aktuellerBenutzername; }
// Direkt beim Start laden public EmployeeTasksViewModel(User benutzer, IZeiterfassungsRepository repository)
_ = LadeEintraegeAsync(); {
_benutzer = benutzer;
_repository = repository;
aktuellerBenutzername = benutzer.Username;
Console.WriteLine($"[DEBUG] ViewModel erstellt für Benutzer: {aktuellerBenutzername}");
_ = LadeEintraegeAsync(); // Lade Daten automatisch beim Öffnen
} }
// Lädt alle Einträge für den Benutzer aus der Datenbank
[RelayCommand] [RelayCommand]
public async Task LadeEintraegeAsync() public async Task LadeEintraegeAsync()
{ {
var eintraegeAusDb = await repository.GetEintraegeFuerMitarbeiterAsync(aktuellerBenutzername); var eintraegeAusDb = await _repository.GetEintraegeFuerMitarbeiterAsync(aktuellerBenutzername);
Eintraege = new ObservableCollection<Zeiteintrag>(eintraegeAusDb);
StatusText = $"🔄 {Eintraege.Count} Einträge geladen."; var offene = eintraegeAusDb
.Where(e => !e.Erledigt)
.OrderBy(e => e.Endzeit)
.ToList();
// 🔔 Setze Markierung für geänderte Aufgaben
foreach (var eintrag in offene)
{
eintrag.WurdeSeitLoginBearbeitet = eintrag.LetzteBearbeitung > _benutzer.LetzterLogin;
// 🔍 Debug-Ausgabe zur Prüfung
Console.WriteLine($"[DEBUG] Eintrag {eintrag.Id}: Endzeit={eintrag.Endzeit}, LetzteBearbeitung={eintrag.LetzteBearbeitung}, LetzterLogin={_benutzer.LetzterLogin}, Markiert={eintrag.WurdeSeitLoginBearbeitet}");
}
if (offene.Any(e => e.WurdeSeitLoginBearbeitet))
StatusText = "📢 Es wurden Aufgaben seit Ihrem letzten Login geändert.";
Eintraege = new ObservableCollection<Zeiteintrag>(offene);
} }
// Speichert Änderungen (Status + Kommentar) für alle sichtbaren Einträge
[RelayCommand] [RelayCommand]
public async Task SpeichereEintraegeAsync() public async Task SpeichereEintraegeAsync()
{ {
foreach (var eintrag in Eintraege) foreach (var eintrag in Eintraege)
{ {
await repository.UpdateStatusUndKommentarAsync(eintrag.Id, eintrag.Erledigt, eintrag.MitarbeiterKommentar); await _repository.UpdateStatusUndKommentarAsync(
eintrag.Id,
eintrag.Erledigt,
eintrag.MitarbeiterKommentar
);
} }
StatusText = "✅ Änderungen gespeichert."; StatusText = "✅ Änderungen gespeichert.";
await LadeEintraegeAsync(); // automatisch neu laden
} }
} }
} }

View File

@ -2,7 +2,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ChronoFlow.View.MitarbeiterHinzufuegenView"> x:Class="ChronoFlow.View.MitarbeiterHinzufuegenView">
<StackPanel Margin="20" Spacing="10"> <ScrollViewer>
<StackPanel Margin="20" Spacing="15">
<TextBlock Text=" Mitarbeiter hinzufügen" FontWeight="Bold" FontSize="20" HorizontalAlignment="Center"/> <TextBlock Text=" Mitarbeiter hinzufügen" FontWeight="Bold" FontSize="20" HorizontalAlignment="Center"/>
<TextBox x:Name="UsernameBox" Watermark="Benutzername"/> <TextBox x:Name="UsernameBox" Watermark="Benutzername"/>
@ -20,4 +21,5 @@
<Button Content="⬅ Zurück zum Dashboard" Click="ZurueckZumDashboard_Click" HorizontalAlignment="Center" Margin="0,10,0,0"/> <Button Content="⬅ Zurück zum Dashboard" Click="ZurueckZumDashboard_Click" HorizontalAlignment="Center" Margin="0,10,0,0"/>
<TextBlock x:Name="FeedbackText" Foreground="Green" IsVisible="False" TextAlignment="Center"/> <TextBlock x:Name="FeedbackText" Foreground="Green" IsVisible="False" TextAlignment="Center"/>
</StackPanel> </StackPanel>
</ScrollViewer>
</UserControl> </UserControl>