CineBook Projekt hinzugefügt
This commit is contained in:
71
Views/AdminPanelView.xaml
Normal file
71
Views/AdminPanelView.xaml
Normal file
@@ -0,0 +1,71 @@
|
||||
<UserControl x:Class="CineBook.Views.AdminPanelView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Background="#0A0A0A">
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="🛠 ADMIN-PANEL — BENUTZERVERWALTUNG"
|
||||
Style="{StaticResource RetroHeader}" Margin="0,0,0,16"/>
|
||||
|
||||
<!-- TOOLBAR -->
|
||||
<Border Grid.Row="1" Background="#111" BorderBrush="#222" BorderThickness="1" Padding="12" Margin="0,0,0,12">
|
||||
<DockPanel>
|
||||
<TextBlock Text="BENUTZERLISTE" Style="{StaticResource RetroLabel}" VerticalAlignment="Center"/>
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="[ + BENUTZER ANLEGEN ]" Style="{StaticResource RetroButtonGreen}"
|
||||
Height="30" Click="AddUserClick"/>
|
||||
<Button x:Name="BtnEditUser" Content="[ ✎ BEARBEITEN ]" Style="{StaticResource RetroButton}"
|
||||
Margin="6,0" Height="30" Click="EditUserClick" IsEnabled="False"/>
|
||||
<Button x:Name="BtnDeleteUser" Content="[ ✕ LÖSCHEN ]" Style="{StaticResource RetroButtonRed}"
|
||||
Height="30" Click="DeleteUserClick" IsEnabled="False"/>
|
||||
<Button Content="[ ↺ AKTUALISIEREN ]" Style="{StaticResource RetroButtonGray}"
|
||||
Margin="6,0,0,0" Height="30" Click="RefreshClick"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<DataGrid x:Name="UsersGrid" Grid.Row="2" Style="{StaticResource RetroDataGrid}"
|
||||
SelectionChanged="GridSelectionChanged">
|
||||
<DataGrid.ColumnHeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="#1a1a1a"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
<Setter Property="FontFamily" Value="Courier New"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Padding" Value="8,6"/>
|
||||
<Setter Property="BorderBrush" Value="#333"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,1,1"/>
|
||||
</Style>
|
||||
</DataGrid.ColumnHeaderStyle>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="#CCC"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#1E1A00"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="ID" Binding="{Binding UserID}" Width="50"/>
|
||||
<DataGridTextColumn Header="BENUTZERNAME" Binding="{Binding Username}" Width="160"/>
|
||||
<DataGridTextColumn Header="ROLLE" Binding="{Binding Role}" Width="100"/>
|
||||
<DataGridTextColumn Header="E-MAIL" Binding="{Binding Email}" Width="*"/>
|
||||
<DataGridTextColumn Header="ERSTELLT AM" Binding="{Binding CreatedAt, StringFormat='dd.MM.yyyy'}" Width="120"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<TextBlock x:Name="StatusText" Grid.Row="3" Style="{StaticResource RetroLabel}"
|
||||
Foreground="#666" Margin="0,8,0,0"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
92
Views/AdminPanelView.xaml.cs
Normal file
92
Views/AdminPanelView.xaml.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using CineBook.Data;
|
||||
using CineBook.Helpers;
|
||||
using CineBook.Models;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class AdminPanelView : UserControl
|
||||
{
|
||||
private readonly Repository _repo;
|
||||
private User? _selected;
|
||||
|
||||
public AdminPanelView(Repository repo)
|
||||
{
|
||||
InitializeComponent();
|
||||
_repo = repo;
|
||||
if (!Session.IsAdmin)
|
||||
{
|
||||
StatusText.Text = "⚠ Kein Zugriff. Nur für Administratoren.";
|
||||
return;
|
||||
}
|
||||
LoadUsers();
|
||||
}
|
||||
|
||||
private void LoadUsers()
|
||||
{
|
||||
try
|
||||
{
|
||||
UsersGrid.ItemsSource = _repo.GetAllUsers();
|
||||
StatusText.Text = $"● {_repo.GetAllUsers().Count} Benutzer geladen.";
|
||||
}
|
||||
catch (System.Exception ex) { StatusText.Text = "⚠ Fehler: " + ex.Message; }
|
||||
}
|
||||
|
||||
private void GridSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
_selected = UsersGrid.SelectedItem as User;
|
||||
BtnEditUser.IsEnabled = _selected != null;
|
||||
BtnDeleteUser.IsEnabled = _selected != null;
|
||||
}
|
||||
|
||||
private void RefreshClick(object sender, RoutedEventArgs e) => LoadUsers();
|
||||
|
||||
private void AddUserClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new UserEditDialog(null);
|
||||
if (dlg.ShowDialog() == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_repo.CreateUser(dlg.Username, dlg.Password, dlg.Role, dlg.Email))
|
||||
LoadUsers();
|
||||
else
|
||||
MessageBox.Show("Fehler beim Anlegen. Benutzername bereits vergeben?", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
catch (System.Exception ex) { MessageBox.Show("DB-Fehler: " + ex.Message); }
|
||||
}
|
||||
}
|
||||
|
||||
private void EditUserClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_selected == null) return;
|
||||
var dlg = new UserEditDialog(_selected);
|
||||
if (dlg.ShowDialog() == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
_repo.UpdateUser(_selected.UserID, dlg.Username, dlg.Role, dlg.Email);
|
||||
LoadUsers();
|
||||
}
|
||||
catch (System.Exception ex) { MessageBox.Show("DB-Fehler: " + ex.Message); }
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteUserClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_selected == null) return;
|
||||
if (_selected.UserID == Session.CurrentUser?.UserID)
|
||||
{
|
||||
MessageBox.Show("Sie können sich nicht selbst löschen!", "Fehler", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
var r = MessageBox.Show($"Benutzer \"{_selected.Username}\" wirklich löschen?",
|
||||
"Bestätigung", MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (r == MessageBoxResult.Yes)
|
||||
{
|
||||
try { _repo.DeleteUser(_selected.UserID); LoadUsers(); }
|
||||
catch (System.Exception ex) { MessageBox.Show("DB-Fehler: " + ex.Message); }
|
||||
}
|
||||
}
|
||||
}
|
||||
77
Views/BookingsView.xaml
Normal file
77
Views/BookingsView.xaml
Normal file
@@ -0,0 +1,77 @@
|
||||
<UserControl x:Class="CineBook.Views.BookingsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Background="#0A0A0A">
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="🎟 BUCHUNGSVERWALTUNG" Style="{StaticResource RetroHeader}" Margin="0,0,0,16"/>
|
||||
|
||||
<Border Grid.Row="1" Background="#111" BorderBrush="#222" BorderThickness="1" Padding="12" Margin="0,0,0,12">
|
||||
<DockPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="STATUS:" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<ComboBox x:Name="StatusFilter" Width="160" Height="30"
|
||||
Background="#111" Foreground="#F5C518" FontFamily="Courier New"
|
||||
SelectionChanged="FilterChanged">
|
||||
<ComboBoxItem>Alle</ComboBoxItem>
|
||||
<ComboBoxItem>Confirmed</ComboBoxItem>
|
||||
<ComboBoxItem>Cancelled</ComboBoxItem>
|
||||
</ComboBox>
|
||||
<Button Content="[ AKTUALISIEREN ]" Style="{StaticResource RetroButtonGray}"
|
||||
Margin="8,0,0,0" Height="30" Click="RefreshClick"/>
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button x:Name="BtnCancel" Content="[ ✕ BUCHUNG STORNIEREN ]" Style="{StaticResource RetroButtonRed}"
|
||||
Height="30" Click="CancelBookingClick" IsEnabled="False"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<DataGrid x:Name="BookingsGrid" Grid.Row="2" Style="{StaticResource RetroDataGrid}"
|
||||
SelectionChanged="GridSelectionChanged">
|
||||
<DataGrid.ColumnHeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="#1a1a1a"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
<Setter Property="FontFamily" Value="Courier New"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Padding" Value="8,6"/>
|
||||
<Setter Property="BorderBrush" Value="#333"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,1,1"/>
|
||||
</Style>
|
||||
</DataGrid.ColumnHeaderStyle>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="#CCC"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#1E1A00"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="CODE" Binding="{Binding BookingCode}" Width="130"/>
|
||||
<DataGridTextColumn Header="BENUTZER" Binding="{Binding Username}" Width="100"/>
|
||||
<DataGridTextColumn Header="FILM" Binding="{Binding MovieTitle}" Width="*"/>
|
||||
<DataGridTextColumn Header="VORFÜHRUNG" Binding="{Binding ScreeningDisplay}" Width="150"/>
|
||||
<DataGridTextColumn Header="SITZ" Binding="{Binding SeatDisplay}" Width="70"/>
|
||||
<DataGridTextColumn Header="PREIS" Binding="{Binding PriceDisplay}" Width="80"/>
|
||||
<DataGridTextColumn Header="STATUS" Binding="{Binding Status}" Width="90"/>
|
||||
<DataGridTextColumn Header="GEBUCHT AM" Binding="{Binding DateDisplay}" Width="130"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<TextBlock x:Name="StatusText" Grid.Row="3" Style="{StaticResource RetroLabel}"
|
||||
Foreground="#666" Margin="0,8,0,0"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
79
Views/BookingsView.xaml.cs
Normal file
79
Views/BookingsView.xaml.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using CineBook.Data;
|
||||
using CineBook.Helpers;
|
||||
using CineBook.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class BookingsView : UserControl
|
||||
{
|
||||
private readonly Repository _repo;
|
||||
private readonly User _currentUser;
|
||||
private Booking? _selected;
|
||||
private List<Booking> _allBookings = new();
|
||||
|
||||
public BookingsView(Repository repo, User user)
|
||||
{
|
||||
InitializeComponent();
|
||||
_repo = repo;
|
||||
_currentUser = user;
|
||||
|
||||
if (!Session.IsAdmin)
|
||||
BtnCancel.Visibility = Visibility.Collapsed;
|
||||
|
||||
StatusFilter.SelectedIndex = 0;
|
||||
LoadBookings();
|
||||
}
|
||||
|
||||
private void LoadBookings()
|
||||
{
|
||||
try
|
||||
{
|
||||
_allBookings = Session.IsAdmin
|
||||
? _repo.GetAllBookings()
|
||||
: _repo.GetBookingsByUser(_currentUser.UserID);
|
||||
ApplyFilter();
|
||||
}
|
||||
catch (System.Exception ex) { StatusText.Text = "⚠ Fehler: " + ex.Message; }
|
||||
}
|
||||
|
||||
private void ApplyFilter()
|
||||
{
|
||||
var filter = (StatusFilter.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "Alle";
|
||||
var data = filter == "Alle" ? _allBookings : _allBookings.Where(b => b.Status == filter).ToList();
|
||||
BookingsGrid.ItemsSource = data;
|
||||
StatusText.Text = $"● {data.Count} Buchungen angezeigt.";
|
||||
}
|
||||
|
||||
private void FilterChanged(object sender, SelectionChangedEventArgs e) => ApplyFilter();
|
||||
private void RefreshClick(object sender, RoutedEventArgs e) => LoadBookings();
|
||||
|
||||
private void GridSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
_selected = BookingsGrid.SelectedItem as Booking;
|
||||
BtnCancel.IsEnabled = _selected != null && _selected.Status == "Confirmed" && Session.IsAdmin;
|
||||
}
|
||||
|
||||
private void CancelBookingClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_selected == null) return;
|
||||
var r = MessageBox.Show($"Buchung {_selected.BookingCode} wirklich stornieren?",
|
||||
"Stornierung", MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (r == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
_repo.CancelBooking(_selected.BookingID, _selected.SeatID, _selected.ScreeningID);
|
||||
LoadBookings();
|
||||
MessageBox.Show("Buchung erfolgreich storniert.", "Erfolg", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
MessageBox.Show("DB-Fehler: " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Views/LoginWindow.xaml
Normal file
48
Views/LoginWindow.xaml
Normal file
@@ -0,0 +1,48 @@
|
||||
<Window x:Class="CineBook.Views.LoginWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="CineBook — Anmeldung" Height="460" Width="400"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ResizeMode="NoResize"
|
||||
Background="#0A0A0A">
|
||||
<Grid>
|
||||
<StackPanel VerticalAlignment="Center" Margin="40">
|
||||
<!-- Logo -->
|
||||
<Border BorderBrush="#F5C518" BorderThickness="2" Padding="20,16" Margin="0,0,0,30">
|
||||
<StackPanel>
|
||||
<TextBlock Text="🎬 CINEBOOK" FontFamily="Courier New" FontSize="28"
|
||||
FontWeight="Bold" Foreground="#F5C518" HorizontalAlignment="Center"/>
|
||||
<TextBlock Text="━━━━━━━━━━━━━━━━━━" Foreground="#444" HorizontalAlignment="Center" Margin="0,4"/>
|
||||
<TextBlock Text="K I N O V E R W A L T U N G S S Y S T E M" FontFamily="Courier New" FontSize="10"
|
||||
Foreground="#888" HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Status -->
|
||||
<TextBlock x:Name="StatusText" Text="" Foreground="#C0392B"
|
||||
FontFamily="Courier New" FontSize="12" HorizontalAlignment="Center"
|
||||
Margin="0,0,0,10" Visibility="Collapsed"/>
|
||||
|
||||
<!-- Username -->
|
||||
<TextBlock Text="BENUTZERNAME" Style="{StaticResource RetroLabel}" Margin="0,0,0,4"/>
|
||||
<TextBox x:Name="UsernameBox" Style="{StaticResource RetroTextBox}"
|
||||
Height="34" Margin="0,0,0,14"
|
||||
KeyDown="InputKeyDown"/>
|
||||
|
||||
<!-- Password -->
|
||||
<TextBlock Text="PASSWORT" Style="{StaticResource RetroLabel}" Margin="0,0,0,4"/>
|
||||
<PasswordBox x:Name="PasswordBox" Style="{StaticResource RetroPasswordBox}"
|
||||
Height="34" Margin="0,0,0,24"
|
||||
KeyDown="InputKeyDown"/>
|
||||
|
||||
<!-- Login Button -->
|
||||
<Button Content="[ ANMELDEN ]" Style="{StaticResource RetroButton}"
|
||||
Height="38" Click="LoginClick"/>
|
||||
|
||||
<!-- Hint -->
|
||||
<TextBlock Text="Demo: admin / admin123 | maria / 1" Foreground="#555"
|
||||
FontFamily="Courier New" FontSize="10" HorizontalAlignment="Center"
|
||||
Margin="0,20,0,0"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
88
Views/LoginWindow.xaml.cs
Normal file
88
Views/LoginWindow.xaml.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using CineBook.Data;
|
||||
using CineBook.Helpers;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class LoginWindow : Window
|
||||
{
|
||||
private readonly Repository _repo;
|
||||
private readonly bool _dbConfigured;
|
||||
|
||||
public LoginWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var cs = DbConfig.GetConnectionString();
|
||||
if (string.IsNullOrWhiteSpace(cs))
|
||||
{
|
||||
MessageBox.Show(
|
||||
"Es ist keine DB-Verbindung konfiguriert.\n\n" +
|
||||
"Bitte setze die Umgebungsvariable 'CINEBOOK_CONNECTION_STRING'.\n" +
|
||||
"(Siehe Kommentar in Data/DbConfig.cs)",
|
||||
"Konfiguration fehlt",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
// Window bleibt offen, damit die Info sichtbar bleibt.
|
||||
_repo = new Repository(new Db(""));
|
||||
_dbConfigured = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var db = new Db(cs);
|
||||
_repo = new Repository(db);
|
||||
_dbConfigured = true;
|
||||
}
|
||||
UsernameBox.Focus();
|
||||
}
|
||||
|
||||
private void LoginClick(object sender, RoutedEventArgs e) => TryLogin();
|
||||
|
||||
private void InputKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter) TryLogin();
|
||||
}
|
||||
|
||||
private void TryLogin()
|
||||
{
|
||||
if (!_dbConfigured)
|
||||
{
|
||||
ShowError("DB-Verbindung nicht konfiguriert (CINEBOOK_CONNECTION_STRING). Login nicht möglich.");
|
||||
return;
|
||||
}
|
||||
var user = UsernameBox.Text.Trim();
|
||||
var pass = PasswordBox.Password;
|
||||
|
||||
if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
|
||||
{
|
||||
ShowError("Bitte Benutzername und Passwort eingeben.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var found = _repo.GetUserByCredentials(user, pass);
|
||||
if (found == null)
|
||||
{
|
||||
ShowError("Falscher Benutzername oder Passwort.");
|
||||
PasswordBox.Clear();
|
||||
return;
|
||||
}
|
||||
Session.CurrentUser = found;
|
||||
var main = new MainWindow();
|
||||
main.Show();
|
||||
Close();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
ShowError("DB-Fehler: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowError(string msg)
|
||||
{
|
||||
StatusText.Text = "⚠ " + msg;
|
||||
StatusText.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
118
Views/MainWindow.xaml
Normal file
118
Views/MainWindow.xaml
Normal file
@@ -0,0 +1,118 @@
|
||||
<Window x:Class="CineBook.Views.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="CineBook — Kino Verwaltungssystem"
|
||||
Height="680" Width="1100"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#0A0A0A">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="56"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="28"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- TOP BAR -->
|
||||
<Border Grid.Row="0" Background="#111" BorderBrush="#F5C518" BorderThickness="0,0,0,2">
|
||||
<DockPanel Margin="16,0">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="🎬" FontSize="22" VerticalAlignment="Center"/>
|
||||
<TextBlock Text=" CINEBOOK" FontFamily="Courier New" FontSize="20"
|
||||
FontWeight="Bold" Foreground="#F5C518" VerticalAlignment="Center"/>
|
||||
<TextBlock Text=" — KINO VERWALTUNGSSYSTEM" FontFamily="Courier New"
|
||||
FontSize="11" Foreground="#666" VerticalAlignment="Center" Margin="4,0,0,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right">
|
||||
<TextBlock x:Name="UserInfoText" FontFamily="Courier New" FontSize="12"
|
||||
Foreground="#888" VerticalAlignment="Center" Margin="0,0,16,0"/>
|
||||
<Button Content="[ ABMELDEN ]" Style="{StaticResource RetroButtonRed}"
|
||||
Height="30" Click="LogoutClick"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<!-- MAIN CONTENT - TAB NAVIGATION -->
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="160"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- SIDEBAR NAV -->
|
||||
<Border Background="#111" BorderBrush="#222" BorderThickness="0,0,2,0">
|
||||
<StackPanel Margin="0,16,0,0">
|
||||
<TextBlock Text="N A V I G A T I O N" FontFamily="Courier New" FontSize="9"
|
||||
Foreground="#555" Margin="16,0,0,10"/>
|
||||
|
||||
<Button x:Name="BtnMovies" Content="🎥 FILME" Click="NavClick"
|
||||
Tag="movies" Style="{StaticResource NavButton}"/>
|
||||
<Button x:Name="BtnScreenings" Content="📅 VORFÜHRUNGEN" Click="NavClick"
|
||||
Tag="screenings" Style="{StaticResource NavButton}"/>
|
||||
<Button x:Name="BtnBookings" Content="🎟 BUCHUNGEN" Click="NavClick"
|
||||
Tag="bookings" Style="{StaticResource NavButton}"/>
|
||||
<Button x:Name="BtnAdmin" Content="🛠 ADMIN" Click="NavClick"
|
||||
Tag="admin" Style="{StaticResource NavButton}" Visibility="Collapsed"/>
|
||||
|
||||
<Separator Background="#222" Margin="16,20"/>
|
||||
|
||||
<TextBlock Text="K O N T O" FontFamily="Courier New" FontSize="9"
|
||||
Foreground="#555" Margin="16,0,0,10"/>
|
||||
<Button x:Name="BtnMine" Content="👤 MEINE BUCHUNGEN" Click="NavClick"
|
||||
Tag="mine" Style="{StaticResource NavButton}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- VIEW AREA -->
|
||||
<ContentControl x:Name="MainContent" Grid.Column="1" Background="#0A0A0A"/>
|
||||
</Grid>
|
||||
|
||||
<!-- STATUS BAR -->
|
||||
<Border Grid.Row="2" Background="#111" BorderBrush="#222" BorderThickness="0,1,0,0">
|
||||
<DockPanel Margin="12,0">
|
||||
<TextBlock x:Name="DbStatusText" FontFamily="Courier New" FontSize="10"
|
||||
Foreground="#555" VerticalAlignment="Center"/>
|
||||
<TextBlock x:Name="StatsText" DockPanel.Dock="Right" FontFamily="Courier New"
|
||||
FontSize="10" Foreground="#555" VerticalAlignment="Center" HorizontalAlignment="Right"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<Window.Resources>
|
||||
<Style x:Key="NavButton" TargetType="Button">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="#888"/>
|
||||
<Setter Property="FontFamily" Value="Courier New"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left"/>
|
||||
<Setter Property="Padding" Value="16,10"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="Bd" Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}">
|
||||
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="{TemplateBinding Padding}"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#1a1a1a"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="NavButtonActive" TargetType="Button" BasedOn="{StaticResource NavButton}">
|
||||
<Setter Property="Background" Value="#1E1A00"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
<Setter Property="BorderThickness" Value="3,0,0,0"/>
|
||||
<Setter Property="BorderBrush" Value="#F5C518"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
</Window>
|
||||
96
Views/MainWindow.xaml.cs
Normal file
96
Views/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using CineBook.Data;
|
||||
using CineBook.Helpers;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private readonly Repository _repo;
|
||||
private Button? _activeNavBtn;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (!Session.IsLoggedIn)
|
||||
{
|
||||
// Schutz gegen NullReference, falls MainWindow direkt gestartet wird.
|
||||
new LoginWindow().Show();
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
var cs = DbConfig.GetConnectionString();
|
||||
if (string.IsNullOrWhiteSpace(cs))
|
||||
{
|
||||
MessageBox.Show(
|
||||
"DB-Verbindung nicht konfiguriert. Bitte setze 'CINEBOOK_CONNECTION_STRING'.",
|
||||
"Konfiguration fehlt",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Error);
|
||||
new LoginWindow().Show();
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
var db = new Db(cs);
|
||||
_repo = new Repository(db);
|
||||
|
||||
UserInfoText.Text = $"[ {Session.CurrentUser!.Username.ToUpper()} | {Session.CurrentUser!.Role.ToUpper()} ]";
|
||||
|
||||
if (Session.IsAdmin)
|
||||
BtnAdmin.Visibility = Visibility.Visible;
|
||||
|
||||
SetStats();
|
||||
Navigate("movies", BtnMovies);
|
||||
}
|
||||
|
||||
private void NavClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Button btn)
|
||||
Navigate(btn.Tag?.ToString() ?? "movies", btn);
|
||||
}
|
||||
|
||||
private void Navigate(string view, Button btn)
|
||||
{
|
||||
if (_activeNavBtn != null)
|
||||
_activeNavBtn.Style = (Style)Resources["NavButton"];
|
||||
btn.Style = (Style)Resources["NavButtonActive"];
|
||||
_activeNavBtn = btn;
|
||||
|
||||
MainContent.Content = view switch
|
||||
{
|
||||
"movies" => new MovieListView(_repo),
|
||||
"screenings" => new ScreeningsView(_repo),
|
||||
"bookings" => new BookingsView(_repo, Session.CurrentUser!),
|
||||
"admin" => new AdminPanelView(_repo),
|
||||
"mine" => new MyBookingsView(_repo, Session.CurrentUser!),
|
||||
_ => new MovieListView(_repo)
|
||||
};
|
||||
}
|
||||
|
||||
private void LogoutClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Session.Logout();
|
||||
new LoginWindow().Show();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void SetStats()
|
||||
{
|
||||
try
|
||||
{
|
||||
var (movies, screenings, bookings, users) = _repo.GetStats();
|
||||
StatsText.Text = $"Filme: {movies} | Vorführungen: {screenings} | Buchungen: {bookings} | Benutzer: {users}";
|
||||
DbStatusText.Text = "● DB VERBUNDEN";
|
||||
DbStatusText.Foreground = System.Windows.Media.Brushes.LimeGreen;
|
||||
}
|
||||
catch
|
||||
{
|
||||
DbStatusText.Text = "● DB NICHT ERREICHBAR";
|
||||
DbStatusText.Foreground = System.Windows.Media.Brushes.Red;
|
||||
}
|
||||
}
|
||||
}
|
||||
74
Views/MovieEditDialog.xaml
Normal file
74
Views/MovieEditDialog.xaml
Normal file
@@ -0,0 +1,74 @@
|
||||
<Window x:Class="CineBook.Views.MovieEditDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Film bearbeiten" Height="420" Width="480"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
ResizeMode="NoResize"
|
||||
Background="#0A0A0A">
|
||||
<Grid Margin="24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock x:Name="DialogTitle" Text="🎥 FILM BEARBEITEN" Style="{StaticResource RetroHeader}"
|
||||
Margin="0,0,0,20"/>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="110"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="TITEL *" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<TextBox x:Name="TitleBox" Grid.Column="1" Style="{StaticResource RetroTextBox}" Height="30" Margin="0,0,0,10"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Text="GENRE" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<ComboBox x:Name="GenreBox" Grid.Row="1" Grid.Column="1" Style="{StaticResource RetroComboBox}"
|
||||
Height="30" Margin="0,0,0,10" Background="#111" Foreground="#F5C518">
|
||||
<ComboBoxItem>Action</ComboBoxItem>
|
||||
<ComboBoxItem>Drama</ComboBoxItem>
|
||||
<ComboBoxItem>Komödie</ComboBoxItem>
|
||||
<ComboBoxItem>Sci-Fi</ComboBoxItem>
|
||||
<ComboBoxItem>Thriller</ComboBoxItem>
|
||||
<ComboBoxItem>Horror</ComboBoxItem>
|
||||
<ComboBoxItem>Dokumentation</ComboBoxItem>
|
||||
<ComboBoxItem>Animation</ComboBoxItem>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="2" Text="DAUER (Min)" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<TextBox x:Name="DurationBox" Grid.Row="2" Grid.Column="1" Style="{StaticResource RetroTextBox}"
|
||||
Height="30" Margin="0,0,0,10"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Text="BEWERTUNG" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<TextBox x:Name="RatingBox" Grid.Row="3" Grid.Column="1" Style="{StaticResource RetroTextBox}"
|
||||
Height="30" Margin="0,0,0,10"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Text="AKTIV" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<CheckBox x:Name="ActiveCheck" Grid.Row="4" Grid.Column="1" IsChecked="True"
|
||||
Foreground="#F5C518" FontFamily="Courier New" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
|
||||
<TextBlock Grid.Row="5" Text="BESCHREIBUNG" Style="{StaticResource RetroLabel}" VerticalAlignment="Top" Margin="0,4,0,0"/>
|
||||
<TextBox x:Name="DescBox" Grid.Row="5" Grid.Column="1" Style="{StaticResource RetroTextBox}"
|
||||
TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Auto"/>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,16,0,0">
|
||||
<TextBlock x:Name="ErrorText" Foreground="#C0392B" FontFamily="Courier New" FontSize="11"
|
||||
VerticalAlignment="Center" Margin="0,0,12,0"/>
|
||||
<Button Content="[ ABBRECHEN ]" Style="{StaticResource RetroButtonGray}"
|
||||
Height="32" Click="CancelClick" Margin="0,0,8,0"/>
|
||||
<Button Content="[ SPEICHERN ]" Style="{StaticResource RetroButtonGreen}"
|
||||
Height="32" Click="SaveClick"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
76
Views/MovieEditDialog.xaml.cs
Normal file
76
Views/MovieEditDialog.xaml.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using CineBook.Models;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class MovieEditDialog : Window
|
||||
{
|
||||
public Movie? Result { get; private set; }
|
||||
private readonly Movie? _editing;
|
||||
|
||||
public MovieEditDialog(Movie? movie)
|
||||
{
|
||||
InitializeComponent();
|
||||
_editing = movie;
|
||||
|
||||
if (movie != null)
|
||||
{
|
||||
DialogTitle.Text = "🎥 FILM BEARBEITEN";
|
||||
TitleBox.Text = movie.Title;
|
||||
// Set genre combobox
|
||||
foreach (ComboBoxItem item in GenreBox.Items)
|
||||
if (item.Content?.ToString() == movie.Genre)
|
||||
GenreBox.SelectedItem = item;
|
||||
DurationBox.Text = movie.DurationMinutes.ToString();
|
||||
RatingBox.Text = movie.Rating.ToString("F1");
|
||||
ActiveCheck.IsChecked = movie.IsActive;
|
||||
DescBox.Text = movie.Description;
|
||||
}
|
||||
else
|
||||
{
|
||||
DialogTitle.Text = "🎥 FILM HINZUFÜGEN";
|
||||
RatingBox.Text = "7.0";
|
||||
ActiveCheck.IsChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Validierung
|
||||
if (string.IsNullOrWhiteSpace(TitleBox.Text))
|
||||
{
|
||||
ErrorText.Text = "⚠ Titel ist Pflichtfeld!"; return;
|
||||
}
|
||||
if (!int.TryParse(DurationBox.Text, out var dur) || dur <= 0)
|
||||
{
|
||||
ErrorText.Text = "⚠ Ungültige Dauer!"; return;
|
||||
}
|
||||
if (!decimal.TryParse(RatingBox.Text.Replace(',', '.'),
|
||||
System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out var rating)
|
||||
|| rating < 0 || rating > 10)
|
||||
{
|
||||
ErrorText.Text = "⚠ Bewertung muss zwischen 0-10 liegen!"; return;
|
||||
}
|
||||
|
||||
Result = new Movie
|
||||
{
|
||||
MovieID = _editing?.MovieID ?? 0,
|
||||
Title = TitleBox.Text.Trim(),
|
||||
Genre = (GenreBox.SelectedItem as ComboBoxItem)?.Content?.ToString() ?? "",
|
||||
DurationMinutes = dur,
|
||||
Rating = rating,
|
||||
IsActive = ActiveCheck.IsChecked == true,
|
||||
Description = DescBox.Text.Trim()
|
||||
};
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void CancelClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
86
Views/MovieListView.xaml
Normal file
86
Views/MovieListView.xaml
Normal file
@@ -0,0 +1,86 @@
|
||||
<UserControl x:Class="CineBook.Views.MovieListView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Background="#0A0A0A">
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- HEADER -->
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,16">
|
||||
<TextBlock Text="🎥 FILMVERWALTUNG" Style="{StaticResource RetroHeader}"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- TOOLBAR -->
|
||||
<Border Grid.Row="1" Background="#111" BorderBrush="#222" BorderThickness="1" Padding="12" Margin="0,0,0,12">
|
||||
<DockPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="SUCHE:" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<TextBox x:Name="SearchBox" Style="{StaticResource RetroTextBox}"
|
||||
Width="220" Height="30" TextChanged="SearchChanged"/>
|
||||
<Button Content="[ SUCHEN ]" Style="{StaticResource RetroButton}"
|
||||
Margin="8,0,0,0" Height="30" Click="SearchClick"/>
|
||||
<Button Content="[ ALLE ]" Style="{StaticResource RetroButtonGray}"
|
||||
Margin="4,0,0,0" Height="30" Click="LoadAllClick"/>
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button x:Name="BtnAdd" Content="[ + HINZUFÜGEN ]" Style="{StaticResource RetroButtonGreen}"
|
||||
Height="30" Click="AddClick"/>
|
||||
<Button x:Name="BtnEdit" Content="[ ✎ BEARBEITEN ]" Style="{StaticResource RetroButton}"
|
||||
Margin="6,0" Height="30" Click="EditClick" IsEnabled="False"/>
|
||||
<Button x:Name="BtnDelete" Content="[ ✕ LÖSCHEN ]" Style="{StaticResource RetroButtonRed}"
|
||||
Height="30" Click="DeleteClick" IsEnabled="False"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<!-- DATA GRID -->
|
||||
<DataGrid x:Name="MoviesGrid" Grid.Row="2" Style="{StaticResource RetroDataGrid}"
|
||||
SelectionChanged="GridSelectionChanged">
|
||||
<DataGrid.ColumnHeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="#1a1a1a"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
<Setter Property="FontFamily" Value="Courier New"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Padding" Value="8,6"/>
|
||||
<Setter Property="BorderBrush" Value="#333"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,1,1"/>
|
||||
</Style>
|
||||
</DataGrid.ColumnHeaderStyle>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="#CCC"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#1E1A00"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="#161200"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="ID" Binding="{Binding MovieID}" Width="50"/>
|
||||
<DataGridTextColumn Header="TITEL" Binding="{Binding Title}" Width="*"/>
|
||||
<DataGridTextColumn Header="GENRE" Binding="{Binding Genre}" Width="100"/>
|
||||
<DataGridTextColumn Header="DAUER" Binding="{Binding DurationDisplay}" Width="90"/>
|
||||
<DataGridTextColumn Header="BEWERTUNG" Binding="{Binding RatingDisplay}" Width="100"/>
|
||||
<DataGridCheckBoxColumn Header="AKTIV" Binding="{Binding IsActive}" Width="70"/>
|
||||
<DataGridTextColumn Header="BESCHREIBUNG" Binding="{Binding Description}" Width="200"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<!-- STATUS -->
|
||||
<TextBlock x:Name="StatusText" Grid.Row="3" Style="{StaticResource RetroLabel}"
|
||||
Foreground="#666" Margin="0,8,0,0"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
120
Views/MovieListView.xaml.cs
Normal file
120
Views/MovieListView.xaml.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using CineBook.Data;
|
||||
using CineBook.Helpers;
|
||||
using CineBook.Models;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class MovieListView : UserControl
|
||||
{
|
||||
private readonly Repository _repo;
|
||||
private Movie? _selected;
|
||||
|
||||
public MovieListView(Repository repo)
|
||||
{
|
||||
InitializeComponent();
|
||||
_repo = repo;
|
||||
|
||||
// Nur Admins dürfen bearbeiten/löschen
|
||||
if (!Session.IsAdmin)
|
||||
{
|
||||
BtnAdd.IsEnabled = false;
|
||||
BtnAdd.Visibility = Visibility.Collapsed;
|
||||
BtnDelete.Visibility = Visibility.Collapsed;
|
||||
BtnEdit.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
LoadMovies();
|
||||
}
|
||||
|
||||
private void LoadMovies()
|
||||
{
|
||||
try
|
||||
{
|
||||
MoviesGrid.ItemsSource = _repo.GetMovies();
|
||||
StatusText.Text = $"● {_repo.GetMovies().Count} Filme geladen.";
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
StatusText.Text = "⚠ Fehler: " + ex.Message;
|
||||
}
|
||||
}
|
||||
|
||||
private void GridSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
_selected = MoviesGrid.SelectedItem as Movie;
|
||||
BtnEdit.IsEnabled = _selected != null && Session.IsAdmin;
|
||||
BtnDelete.IsEnabled = _selected != null && Session.IsAdmin;
|
||||
}
|
||||
|
||||
private void SearchChanged(object sender, TextChangedEventArgs e) { }
|
||||
private void SearchClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var term = SearchBox.Text.Trim();
|
||||
if (string.IsNullOrEmpty(term)) { LoadMovies(); return; }
|
||||
try { MoviesGrid.ItemsSource = _repo.SearchMovies(term); }
|
||||
catch (System.Exception ex) { StatusText.Text = "⚠ " + ex.Message; }
|
||||
}
|
||||
|
||||
private void LoadAllClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SearchBox.Text = "";
|
||||
LoadMovies();
|
||||
}
|
||||
|
||||
private void AddClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new MovieEditDialog(null);
|
||||
if (dlg.ShowDialog() == true && dlg.Result != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_repo.CreateMovie(dlg.Result))
|
||||
LoadMovies();
|
||||
else
|
||||
MessageBox.Show("Fehler beim Speichern.", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
MessageBox.Show("DB-Fehler: " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EditClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_selected == null) return;
|
||||
var dlg = new MovieEditDialog(_selected);
|
||||
if (dlg.ShowDialog() == true && dlg.Result != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_repo.UpdateMovie(dlg.Result))
|
||||
LoadMovies();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
MessageBox.Show("DB-Fehler: " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_selected == null) return;
|
||||
var r = MessageBox.Show($"Film \"{_selected.Title}\" wirklich löschen?", "Bestätigung",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (r == MessageBoxResult.Yes)
|
||||
{
|
||||
try
|
||||
{
|
||||
_repo.DeleteMovie(_selected.MovieID);
|
||||
LoadMovies();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
MessageBox.Show("DB-Fehler: " + ex.Message, "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
84
Views/MyBookingsView.xaml
Normal file
84
Views/MyBookingsView.xaml
Normal file
@@ -0,0 +1,84 @@
|
||||
<UserControl x:Class="CineBook.Views.MyBookingsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Background="#0A0A0A">
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0" Margin="0,0,0,16">
|
||||
<TextBlock Text="👤 MEINE BUCHUNGEN" Style="{StaticResource RetroHeader}"/>
|
||||
<TextBlock x:Name="UserNameText" FontFamily="Courier New" FontSize="11" Foreground="#666" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- STATS PANEL -->
|
||||
<Border Grid.Row="1" Background="#111" BorderBrush="#222" BorderThickness="1" Padding="16,12" Margin="0,0,0,14">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Border Background="#1B2E1B" BorderBrush="#27AE60" BorderThickness="1" Padding="16,8" CornerRadius="2" Margin="0,0,12,0">
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="TotalBookingsText" Text="0" FontFamily="Courier New" FontSize="22"
|
||||
FontWeight="Bold" Foreground="#27AE60" HorizontalAlignment="Center"/>
|
||||
<TextBlock Text="BUCHUNGEN" FontFamily="Courier New" FontSize="9" Foreground="#555" HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Background="#2A1A00" BorderBrush="#F5C518" BorderThickness="1" Padding="16,8" CornerRadius="2" Margin="0,0,12,0">
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="TotalSpentText" Text="0 €" FontFamily="Courier New" FontSize="22"
|
||||
FontWeight="Bold" Foreground="#F5C518" HorizontalAlignment="Center"/>
|
||||
<TextBlock Text="AUSGEGEBEN" FontFamily="Courier New" FontSize="9" Foreground="#555" HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Background="#2A1A1A" BorderBrush="#C0392B" BorderThickness="1" Padding="16,8" CornerRadius="2">
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="ActiveBookingsText" Text="0" FontFamily="Courier New" FontSize="22"
|
||||
FontWeight="Bold" Foreground="#C0392B" HorizontalAlignment="Center"/>
|
||||
<TextBlock Text="AKTIV" FontFamily="Courier New" FontSize="9" Foreground="#555" HorizontalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<DataGrid x:Name="MyGrid" Grid.Row="2" Style="{StaticResource RetroDataGrid}">
|
||||
<DataGrid.ColumnHeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="#1a1a1a"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
<Setter Property="FontFamily" Value="Courier New"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Padding" Value="8,6"/>
|
||||
<Setter Property="BorderBrush" Value="#333"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,1,1"/>
|
||||
</Style>
|
||||
</DataGrid.ColumnHeaderStyle>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="#CCC"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#1E1A00"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="BUCHUNGSCODE" Binding="{Binding BookingCode}" Width="140"/>
|
||||
<DataGridTextColumn Header="FILM" Binding="{Binding MovieTitle}" Width="*"/>
|
||||
<DataGridTextColumn Header="VORFÜHRUNG" Binding="{Binding ScreeningDisplay}" Width="150"/>
|
||||
<DataGridTextColumn Header="SITZ" Binding="{Binding SeatDisplay}" Width="70"/>
|
||||
<DataGridTextColumn Header="PREIS" Binding="{Binding PriceDisplay}" Width="80"/>
|
||||
<DataGridTextColumn Header="STATUS" Binding="{Binding Status}" Width="100"/>
|
||||
<DataGridTextColumn Header="DATUM" Binding="{Binding DateDisplay}" Width="130"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<TextBlock x:Name="StatusText" Grid.Row="3" Style="{StaticResource RetroLabel}"
|
||||
Foreground="#666" Margin="0,8,0,0"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
36
Views/MyBookingsView.xaml.cs
Normal file
36
Views/MyBookingsView.xaml.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using CineBook.Data;
|
||||
using CineBook.Models;
|
||||
using System.Linq;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class MyBookingsView : UserControl
|
||||
{
|
||||
private readonly Repository _repo;
|
||||
private readonly User _user;
|
||||
|
||||
public MyBookingsView(Repository repo, User user)
|
||||
{
|
||||
InitializeComponent();
|
||||
_repo = repo;
|
||||
_user = user;
|
||||
UserNameText.Text = $"Angemeldet als: {user.Username} ({user.Role}) | {user.Email}";
|
||||
Load();
|
||||
}
|
||||
|
||||
private void Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
var bookings = _repo.GetBookingsByUser(_user.UserID);
|
||||
MyGrid.ItemsSource = bookings;
|
||||
|
||||
TotalBookingsText.Text = bookings.Count.ToString();
|
||||
TotalSpentText.Text = bookings.Where(b => b.Status == "Confirmed").Sum(b => b.TotalPrice).ToString("F2") + " €";
|
||||
ActiveBookingsText.Text = bookings.Count(b => b.Status == "Confirmed").ToString();
|
||||
StatusText.Text = $"● {bookings.Count} Buchungen gefunden.";
|
||||
}
|
||||
catch (System.Exception ex) { StatusText.Text = "⚠ Fehler: " + ex.Message; }
|
||||
}
|
||||
}
|
||||
64
Views/ScreeningEditDialog.xaml
Normal file
64
Views/ScreeningEditDialog.xaml
Normal file
@@ -0,0 +1,64 @@
|
||||
<Window x:Class="CineBook.Views.ScreeningEditDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Neue Vorführung" Height="360" Width="440"
|
||||
WindowStartupLocation="CenterOwner" ResizeMode="NoResize"
|
||||
Background="#0A0A0A">
|
||||
<Grid Margin="24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="📅 NEUE VORFÜHRUNG" Style="{StaticResource RetroHeader}" Margin="0,0,0,20"/>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="110"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="FILM *" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<ComboBox x:Name="MovieBox" Grid.Column="1" Height="30" Margin="0,0,0,10"
|
||||
Background="#111" Foreground="#F5C518" FontFamily="Courier New"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Text="DATUM *" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<DatePicker x:Name="DatePicker" Grid.Row="1" Grid.Column="1" Height="30" Margin="0,0,0,10"
|
||||
Background="#111" Foreground="#F5C518" FontFamily="Courier New"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Text="UHRZEIT *" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<TextBox x:Name="TimeBox" Grid.Row="2" Grid.Column="1" Style="{StaticResource RetroTextBox}"
|
||||
Height="30" Margin="0,0,0,10" Text="18:00"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Text="SAAL *" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<ComboBox x:Name="HallBox" Grid.Row="3" Grid.Column="1" Height="30" Margin="0,0,0,10"
|
||||
Background="#111" Foreground="#F5C518" FontFamily="Courier New">
|
||||
<ComboBoxItem>Saal 1</ComboBoxItem>
|
||||
<ComboBoxItem>Saal 2</ComboBoxItem>
|
||||
<ComboBoxItem>Saal 3</ComboBoxItem>
|
||||
<ComboBoxItem>VIP-Saal</ComboBoxItem>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="4" Text="PREIS (€) *" Style="{StaticResource RetroLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox x:Name="PriceBox" Grid.Row="4" Grid.Column="1" Style="{StaticResource RetroTextBox}"
|
||||
Height="30" Text="12.00"/>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,16,0,0">
|
||||
<TextBlock x:Name="ErrorText" Foreground="#C0392B" FontFamily="Courier New" FontSize="11"
|
||||
VerticalAlignment="Center" Margin="0,0,12,0"/>
|
||||
<Button Content="[ ABBRECHEN ]" Style="{StaticResource RetroButtonGray}" Height="32"
|
||||
Click="CancelClick" Margin="0,0,8,0"/>
|
||||
<Button Content="[ SPEICHERN ]" Style="{StaticResource RetroButtonGreen}" Height="32"
|
||||
Click="SaveClick"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
87
Views/ScreeningEditDialog.xaml.cs
Normal file
87
Views/ScreeningEditDialog.xaml.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using CineBook.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class ScreeningEditDialog : Window
|
||||
{
|
||||
public Screening? Result { get; private set; }
|
||||
private readonly List<Movie> _movies;
|
||||
private readonly Screening? _edit;
|
||||
|
||||
public ScreeningEditDialog(List<Movie> movies, Screening? edit = null)
|
||||
{
|
||||
InitializeComponent();
|
||||
_movies = movies;
|
||||
_edit = edit;
|
||||
|
||||
foreach (var m in movies)
|
||||
MovieBox.Items.Add(new ComboBoxItem { Content = m.Title, Tag = m.MovieID, Foreground = System.Windows.Media.Brushes.Gold, FontFamily = new System.Windows.Media.FontFamily("Courier New") });
|
||||
|
||||
if (MovieBox.Items.Count > 0) MovieBox.SelectedIndex = 0;
|
||||
HallBox.SelectedIndex = 0;
|
||||
DatePicker.SelectedDate = DateTime.Today.AddDays(1);
|
||||
|
||||
if (_edit != null)
|
||||
{
|
||||
Title = "Vorführung bearbeiten";
|
||||
// Film vorauswählen
|
||||
for (var i = 0; i < MovieBox.Items.Count; i++)
|
||||
{
|
||||
if (MovieBox.Items[i] is ComboBoxItem ci && (int)ci.Tag == _edit.MovieID)
|
||||
{
|
||||
MovieBox.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DatePicker.SelectedDate = _edit.ScreeningDate;
|
||||
TimeBox.Text = _edit.StartTime.ToString(@"hh\:mm");
|
||||
|
||||
// Hall vorauswählen
|
||||
for (var i = 0; i < HallBox.Items.Count; i++)
|
||||
{
|
||||
if (HallBox.Items[i] is ComboBoxItem hi && (hi.Content?.ToString() ?? "") == _edit.Hall)
|
||||
{
|
||||
HallBox.SelectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PriceBox.Text = _edit.PricePerSeat.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (MovieBox.SelectedItem is not ComboBoxItem mi) { ErrorText.Text = "⚠ Film auswählen!"; return; }
|
||||
if (DatePicker.SelectedDate == null) { ErrorText.Text = "⚠ Datum auswählen!"; return; }
|
||||
if (!TimeSpan.TryParse(TimeBox.Text, out var time)) { ErrorText.Text = "⚠ Uhrzeit ungültig (HH:MM)!"; return; }
|
||||
if (HallBox.SelectedItem is not ComboBoxItem hi) { ErrorText.Text = "⚠ Saal auswählen!"; return; }
|
||||
if (!decimal.TryParse(PriceBox.Text.Replace(',', '.'),
|
||||
System.Globalization.NumberStyles.Any,
|
||||
System.Globalization.CultureInfo.InvariantCulture, out var price) || price <= 0)
|
||||
{ ErrorText.Text = "⚠ Ungültiger Preis!"; return; }
|
||||
|
||||
Result = new Screening
|
||||
{
|
||||
ScreeningID = _edit?.ScreeningID ?? 0,
|
||||
MovieID = (int)mi.Tag,
|
||||
ScreeningDate = DatePicker.SelectedDate.Value,
|
||||
StartTime = time,
|
||||
Hall = hi.Content?.ToString() ?? "Saal 1",
|
||||
// Seats werden beim Anlegen im Repository automatisch erzeugt.
|
||||
// Beim Bearbeiten werden TotalSeats/AvailableSeats nicht verändert (damit Buchungen konsistent bleiben).
|
||||
TotalSeats = _edit?.TotalSeats ?? 80,
|
||||
AvailableSeats = _edit?.AvailableSeats ?? 80,
|
||||
PricePerSeat = price
|
||||
};
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void CancelClick(object sender, RoutedEventArgs e) { DialogResult = false; Close(); }
|
||||
}
|
||||
73
Views/ScreeningsView.xaml
Normal file
73
Views/ScreeningsView.xaml
Normal file
@@ -0,0 +1,73 @@
|
||||
<UserControl x:Class="CineBook.Views.ScreeningsView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Background="#0A0A0A">
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Text="📅 VORFÜHRUNGEN" Style="{StaticResource RetroHeader}" Margin="0,0,0,16"/>
|
||||
<Border Grid.Row="1" Background="#111" BorderBrush="#222" BorderThickness="1" Padding="12" Margin="0,0,0,12">
|
||||
<DockPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="FILM-FILTER:" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<ComboBox x:Name="MovieFilter" Width="200" Height="30"
|
||||
Background="#111" Foreground="#F5C518" FontFamily="Courier New"
|
||||
SelectionChanged="FilterChanged"/>
|
||||
<Button Content="[ ALLE ]" Style="{StaticResource RetroButtonGray}"
|
||||
Margin="8,0,0,0" Height="30" Click="LoadAllClick"/>
|
||||
</StackPanel>
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button x:Name="BtnAdd" Content="[ + NEUE VORFÜHRUNG ]" Style="{StaticResource RetroButtonGreen}"
|
||||
Height="30" Click="AddClick"/>
|
||||
<Button x:Name="BtnEdit" Content="[ ✎ BEARBEITEN ]" Style="{StaticResource RetroButtonGray}"
|
||||
Margin="6,0,0,0" Height="30" Click="EditClick" IsEnabled="False"/>
|
||||
<Button x:Name="BtnDelete" Content="[ ✕ LÖSCHEN ]" Style="{StaticResource RetroButtonRed}"
|
||||
Margin="6,0,0,0" Height="30" Click="DeleteClick" IsEnabled="False"/>
|
||||
<Button x:Name="BtnBookSeat" Content="[ 🎟 TICKET BUCHEN ]" Style="{StaticResource RetroButton}"
|
||||
Margin="6,0,0,0" Height="30" Click="BookSeatClick" IsEnabled="False"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
<DataGrid x:Name="ScreeningsGrid" Grid.Row="2" Style="{StaticResource RetroDataGrid}"
|
||||
SelectionChanged="GridSelectionChanged">
|
||||
<DataGrid.ColumnHeaderStyle>
|
||||
<Style TargetType="DataGridColumnHeader">
|
||||
<Setter Property="Background" Value="#1a1a1a"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
<Setter Property="FontFamily" Value="Courier New"/>
|
||||
<Setter Property="FontWeight" Value="Bold"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Padding" Value="8,6"/>
|
||||
<Setter Property="BorderBrush" Value="#333"/>
|
||||
<Setter Property="BorderThickness" Value="0,0,1,1"/>
|
||||
</Style>
|
||||
</DataGrid.ColumnHeaderStyle>
|
||||
<DataGrid.RowStyle>
|
||||
<Style TargetType="DataGridRow">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="#CCC"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter Property="Background" Value="#1E1A00"/>
|
||||
<Setter Property="Foreground" Value="#F5C518"/>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</DataGrid.RowStyle>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="ID" Binding="{Binding ScreeningID}" Width="50"/>
|
||||
<DataGridTextColumn Header="FILM" Binding="{Binding MovieTitle}" Width="*"/>
|
||||
<DataGridTextColumn Header="DATUM/ZEIT" Binding="{Binding DateTimeDisplay}" Width="160"/>
|
||||
<DataGridTextColumn Header="SAAL" Binding="{Binding Hall}" Width="80"/>
|
||||
<DataGridTextColumn Header="FREIE SITZE" Binding="{Binding SeatsDisplay}" Width="110"/>
|
||||
<DataGridTextColumn Header="PREIS" Binding="{Binding PriceDisplay}" Width="90"/>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<TextBlock x:Name="StatusText" Grid.Row="3" Style="{StaticResource RetroLabel}"
|
||||
Foreground="#666" Margin="0,8,0,0"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
158
Views/ScreeningsView.xaml.cs
Normal file
158
Views/ScreeningsView.xaml.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
using CineBook.Data;
|
||||
using CineBook.Helpers;
|
||||
using CineBook.Models;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class ScreeningsView : UserControl
|
||||
{
|
||||
private readonly Repository _repo;
|
||||
private Screening? _selected;
|
||||
|
||||
public ScreeningsView(Repository repo)
|
||||
{
|
||||
InitializeComponent();
|
||||
_repo = repo;
|
||||
if (!Session.IsAdmin)
|
||||
{
|
||||
BtnAdd.Visibility = Visibility.Collapsed;
|
||||
BtnEdit.Visibility = Visibility.Collapsed;
|
||||
BtnDelete.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
LoadMovieFilter();
|
||||
LoadScreenings();
|
||||
}
|
||||
|
||||
private void LoadMovieFilter()
|
||||
{
|
||||
try
|
||||
{
|
||||
var movies = _repo.GetMovies(onlyActive: true);
|
||||
MovieFilter.Items.Clear();
|
||||
MovieFilter.Items.Add(new ComboBoxItem { Content = "— Alle Filme —", Tag = 0, Foreground = System.Windows.Media.Brushes.Gray, FontFamily = new System.Windows.Media.FontFamily("Courier New") });
|
||||
foreach (var m in movies)
|
||||
MovieFilter.Items.Add(new ComboBoxItem { Content = m.Title, Tag = m.MovieID, Foreground = System.Windows.Media.Brushes.Gold, FontFamily = new System.Windows.Media.FontFamily("Courier New") });
|
||||
MovieFilter.SelectedIndex = 0;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
private void LoadScreenings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var list = _repo.GetScreenings();
|
||||
ScreeningsGrid.ItemsSource = list;
|
||||
StatusText.Text = $"● {list.Count} Vorführungen geladen.";
|
||||
}
|
||||
catch (System.Exception ex) { StatusText.Text = "⚠ Fehler: " + ex.Message; }
|
||||
}
|
||||
|
||||
private void FilterChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (MovieFilter.SelectedItem is ComboBoxItem item && item.Tag is int id && id > 0)
|
||||
{
|
||||
try { ScreeningsGrid.ItemsSource = _repo.GetScreeningsByMovie(id); }
|
||||
catch (System.Exception ex) { StatusText.Text = "⚠ " + ex.Message; }
|
||||
}
|
||||
else LoadScreenings();
|
||||
}
|
||||
|
||||
private void GridSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
_selected = ScreeningsGrid.SelectedItem as Screening;
|
||||
BtnDelete.IsEnabled = _selected != null && Session.IsAdmin;
|
||||
BtnEdit.IsEnabled = _selected != null && Session.IsAdmin;
|
||||
BtnBookSeat.IsEnabled = _selected != null && _selected.AvailableSeats > 0;
|
||||
}
|
||||
|
||||
private void LoadAllClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MovieFilter.SelectedIndex = 0;
|
||||
LoadScreenings();
|
||||
}
|
||||
|
||||
private void AddClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var movies = _repo.GetMovies(onlyActive: true);
|
||||
var dlg = new ScreeningEditDialog(movies);
|
||||
if (dlg.ShowDialog() == true && dlg.Result != null)
|
||||
{
|
||||
try { _repo.CreateScreening(dlg.Result); LoadScreenings(); LoadMovieFilter(); }
|
||||
catch (System.Exception ex) { MessageBox.Show("DB-Fehler: " + ex.Message); }
|
||||
}
|
||||
}
|
||||
|
||||
private void EditClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_selected == null) return;
|
||||
var movies = _repo.GetMovies(onlyActive: true);
|
||||
var dlg = new ScreeningEditDialog(movies, _selected);
|
||||
if (dlg.ShowDialog() == true && dlg.Result != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_repo.UpdateScreening(dlg.Result))
|
||||
LoadScreenings();
|
||||
else
|
||||
MessageBox.Show("Fehler beim Speichern.", "Fehler", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
MessageBox.Show("DB-Fehler: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_selected == null) return;
|
||||
var r = MessageBox.Show($"Vorführung löschen?", "Bestätigung", MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
if (r == MessageBoxResult.Yes)
|
||||
{
|
||||
try { _repo.DeleteScreening(_selected.ScreeningID); LoadScreenings(); }
|
||||
catch (System.Exception ex) { MessageBox.Show("DB-Fehler: " + ex.Message); }
|
||||
}
|
||||
}
|
||||
|
||||
private void BookSeatClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_selected == null) return;
|
||||
var seats = _repo.GetSeatsByScreening(_selected.ScreeningID);
|
||||
if (seats.Count == 0)
|
||||
{
|
||||
if (Session.IsAdmin)
|
||||
{
|
||||
var r = MessageBox.Show(
|
||||
"Für diese Vorführung existieren noch keine Sitzplätze.\nSoll jetzt automatisch ein Sitzplan erstellt werden?",
|
||||
"Sitzplan fehlt",
|
||||
MessageBoxButton.YesNo,
|
||||
MessageBoxImage.Question);
|
||||
if (r == MessageBoxResult.Yes)
|
||||
{
|
||||
if (_repo.EnsureSeatsForScreening(_selected.ScreeningID, _selected.TotalSeats))
|
||||
seats = _repo.GetSeatsByScreening(_selected.ScreeningID);
|
||||
}
|
||||
}
|
||||
if (seats.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Keine Sitzplatzdaten verfügbar.", "Hinweis");
|
||||
return;
|
||||
}
|
||||
}
|
||||
var dlg = new SeatSelectionDialog(_selected, seats, Session.CurrentUser!);
|
||||
if (dlg.ShowDialog() == true)
|
||||
{
|
||||
try
|
||||
{
|
||||
_repo.CreateBooking(Session.CurrentUser!.UserID, dlg.SelectedScreeningId, dlg.SelectedSeatId, dlg.TotalPrice);
|
||||
LoadScreenings();
|
||||
MessageBox.Show($"✓ Buchung erfolgreich!\nSitz: {dlg.SeatDisplay}\nPreis: {dlg.TotalPrice:F2} €",
|
||||
"Buchung bestätigt", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (System.Exception ex) { MessageBox.Show("DB-Fehler: " + ex.Message); }
|
||||
}
|
||||
}
|
||||
}
|
||||
54
Views/SeatSelectionDialog.xaml
Normal file
54
Views/SeatSelectionDialog.xaml
Normal file
@@ -0,0 +1,54 @@
|
||||
<Window x:Class="CineBook.Views.SeatSelectionDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Sitzplatz wählen" Height="500" Width="560"
|
||||
WindowStartupLocation="CenterOwner" ResizeMode="NoResize"
|
||||
Background="#0A0A0A">
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Text="🎟 SITZPLATZ AUSWAHL" Style="{StaticResource RetroHeader}" Margin="0,0,0,8"/>
|
||||
<Border Grid.Row="1" Background="#111" BorderBrush="#333" BorderThickness="1" Padding="12,8" Margin="0,0,0,16">
|
||||
<StackPanel>
|
||||
<TextBlock x:Name="MovieInfoText" FontFamily="Courier New" FontSize="13" Foreground="#F5C518"/>
|
||||
<TextBlock x:Name="ScreeningInfoText" FontFamily="Courier New" FontSize="11" Foreground="#888" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,12">
|
||||
<Border Width="20" Height="20" Background="#27AE60" CornerRadius="2" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="Frei" FontFamily="Courier New" FontSize="11" Foreground="#888" Margin="0,0,16,0" VerticalAlignment="Center"/>
|
||||
<Border Width="20" Height="20" Background="#C0392B" CornerRadius="2" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="Belegt" FontFamily="Courier New" FontSize="11" Foreground="#888" Margin="0,0,16,0" VerticalAlignment="Center"/>
|
||||
<Border Width="20" Height="20" Background="#F5C518" CornerRadius="2" Margin="0,0,4,0"/>
|
||||
<TextBlock Text="Ausgewählt" FontFamily="Courier New" FontSize="11" Foreground="#888" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<Border Background="#222" Height="8" CornerRadius="4" Margin="20,0,20,16">
|
||||
<TextBlock Text="L E I N W A N D" FontFamily="Courier New" FontSize="8"
|
||||
Foreground="#555" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ItemsControl x:Name="SeatsPanel"/>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<Border Grid.Row="3" Background="#111" BorderBrush="#333" BorderThickness="1" Padding="12,8" Margin="0,12,0,12">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="AUSGEWÄHLT: " FontFamily="Courier New" FontSize="12" Foreground="#888" VerticalAlignment="Center"/>
|
||||
<TextBlock x:Name="SelectedSeatText" FontFamily="Courier New" FontSize="12" Foreground="#F5C518" VerticalAlignment="Center"/>
|
||||
<TextBlock Text=" | PREIS: " FontFamily="Courier New" FontSize="12" Foreground="#888" VerticalAlignment="Center"/>
|
||||
<TextBlock x:Name="PriceText" FontFamily="Courier New" FontSize="12" Foreground="#27AE60" FontWeight="Bold" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<StackPanel Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="[ ABBRECHEN ]" Style="{StaticResource RetroButtonGray}" Height="32"
|
||||
Click="CancelClick" Margin="0,0,8,0"/>
|
||||
<Button x:Name="BtnConfirm" Content="[ ✓ BUCHUNG BESTÄTIGEN ]" Style="{StaticResource RetroButtonGreen}"
|
||||
Height="32" Click="ConfirmClick" IsEnabled="False"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
141
Views/SeatSelectionDialog.xaml.cs
Normal file
141
Views/SeatSelectionDialog.xaml.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using CineBook.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class SeatSelectionDialog : Window
|
||||
{
|
||||
private readonly Screening _screening;
|
||||
private readonly List<Seat> _seats;
|
||||
private Seat? _selectedSeat;
|
||||
|
||||
public int SelectedSeatId => _selectedSeat?.SeatID ?? 0;
|
||||
public int SelectedScreeningId => _screening.ScreeningID;
|
||||
public decimal TotalPrice => _screening.PricePerSeat;
|
||||
public string SeatDisplay => _selectedSeat?.Display ?? "";
|
||||
|
||||
public SeatSelectionDialog(Screening screening, List<Seat> seats, User user)
|
||||
{
|
||||
InitializeComponent();
|
||||
_screening = screening;
|
||||
_seats = seats;
|
||||
|
||||
MovieInfoText.Text = screening.MovieTitle;
|
||||
ScreeningInfoText.Text = $"{screening.DateTimeDisplay} | {screening.Hall} | {screening.PriceDisplay} pro Sitz";
|
||||
|
||||
BuildSeatGrid();
|
||||
UpdateSelection();
|
||||
}
|
||||
|
||||
private void BuildSeatGrid()
|
||||
{
|
||||
var rows = _seats.GroupBy(s => s.Row).OrderBy(g => g.Key);
|
||||
var panel = new StackPanel();
|
||||
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var rowPanel = new StackPanel
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
Margin = new Thickness(0, 2, 0, 2)
|
||||
};
|
||||
rowPanel.Children.Add(new TextBlock
|
||||
{
|
||||
Text = row.Key,
|
||||
Width = 24,
|
||||
Foreground = Brushes.Gray,
|
||||
FontFamily = new FontFamily("Courier New"),
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
HorizontalAlignment = HorizontalAlignment.Center
|
||||
});
|
||||
|
||||
foreach (var seat in row.OrderBy(s => s.SeatNumber))
|
||||
{
|
||||
var btn = new Button
|
||||
{
|
||||
Content = seat.SeatNumber.ToString(),
|
||||
Width = 34,
|
||||
Height = 30,
|
||||
Margin = new Thickness(2),
|
||||
FontFamily = new FontFamily("Courier New"),
|
||||
FontSize = 11,
|
||||
Tag = seat,
|
||||
IsEnabled = !seat.IsBooked,
|
||||
Background = seat.IsBooked
|
||||
? new SolidColorBrush(Color.FromRgb(0x44, 0x22, 0x22))
|
||||
: new SolidColorBrush(Color.FromRgb(0x1B, 0x4D, 0x2A)),
|
||||
Foreground = seat.IsBooked ? Brushes.DarkRed : Brushes.LightGreen,
|
||||
BorderBrush = seat.IsBooked
|
||||
? new SolidColorBrush(Color.FromRgb(0x80, 0x20, 0x20))
|
||||
: new SolidColorBrush(Color.FromRgb(0x27, 0xAE, 0x60)),
|
||||
BorderThickness = new Thickness(1),
|
||||
Cursor = seat.IsBooked
|
||||
? System.Windows.Input.Cursors.No
|
||||
: System.Windows.Input.Cursors.Hand
|
||||
};
|
||||
btn.ToolTip = $"Reihe {seat.Row}, Sitz {seat.SeatNumber} ({seat.Category})";
|
||||
btn.Click += SeatClick;
|
||||
rowPanel.Children.Add(btn);
|
||||
}
|
||||
panel.Children.Add(rowPanel);
|
||||
}
|
||||
|
||||
SeatsPanel.ItemsSource = new[] { new ContentControl { Content = panel } };
|
||||
}
|
||||
|
||||
private void SeatClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Button btn || btn.Tag is not Seat seat) return;
|
||||
_selectedSeat = seat;
|
||||
UpdateSelection();
|
||||
|
||||
foreach (var child in FindVisualChildren<Button>(SeatsPanel))
|
||||
{
|
||||
if (child.Tag is Seat s && !s.IsBooked)
|
||||
{
|
||||
bool isSel = s.SeatID == seat.SeatID;
|
||||
child.Background = isSel
|
||||
? new SolidColorBrush(Color.FromRgb(0x7A, 0x62, 0x00))
|
||||
: new SolidColorBrush(Color.FromRgb(0x1B, 0x4D, 0x2A));
|
||||
child.Foreground = isSel ? Brushes.Gold : Brushes.LightGreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateSelection()
|
||||
{
|
||||
SelectedSeatText.Text = _selectedSeat != null
|
||||
? $"Reihe {_selectedSeat.Row}, Sitz {_selectedSeat.SeatNumber} ({_selectedSeat.Category})"
|
||||
: "— kein Sitz gewählt —";
|
||||
PriceText.Text = _selectedSeat != null ? $"{_screening.PricePerSeat:F2} €" : "";
|
||||
BtnConfirm.IsEnabled = _selectedSeat != null;
|
||||
}
|
||||
|
||||
private void ConfirmClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_selectedSeat == null) return;
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void CancelClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
DialogResult = false;
|
||||
Close();
|
||||
}
|
||||
|
||||
private static IEnumerable<T> FindVisualChildren<T>(DependencyObject parent) where T : DependencyObject
|
||||
{
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
|
||||
{
|
||||
var child = VisualTreeHelper.GetChild(parent, i);
|
||||
if (child is T t) yield return t;
|
||||
foreach (var sub in FindVisualChildren<T>(child))
|
||||
yield return sub;
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Views/UserEditDialog.xaml
Normal file
56
Views/UserEditDialog.xaml
Normal file
@@ -0,0 +1,56 @@
|
||||
<Window x:Class="CineBook.Views.UserEditDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Benutzer bearbeiten" Height="340" Width="420"
|
||||
WindowStartupLocation="CenterOwner" ResizeMode="NoResize"
|
||||
Background="#0A0A0A">
|
||||
<Grid Margin="24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock x:Name="DialogTitle" Text="👤 BENUTZER BEARBEITEN"
|
||||
Style="{StaticResource RetroHeader}" Margin="0,0,0,20"/>
|
||||
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="110"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="BENUTZERNAME *" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<TextBox x:Name="UsernameBox" Grid.Column="1" Style="{StaticResource RetroTextBox}" Height="30" Margin="0,0,0,10"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Text="PASSWORT" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<PasswordBox x:Name="PasswordBox" Grid.Row="1" Grid.Column="1" Style="{StaticResource RetroPasswordBox}"
|
||||
Height="30" Margin="0,0,0,10"/>
|
||||
|
||||
<TextBlock Grid.Row="2" Text="ROLLE *" Style="{StaticResource RetroLabel}" VerticalAlignment="Center" Margin="0,0,0,10"/>
|
||||
<ComboBox x:Name="RoleBox" Grid.Row="2" Grid.Column="1" Height="30" Margin="0,0,0,10"
|
||||
Background="#111" Foreground="#F5C518" FontFamily="Courier New">
|
||||
<ComboBoxItem>User</ComboBoxItem>
|
||||
<ComboBoxItem>Admin</ComboBoxItem>
|
||||
</ComboBox>
|
||||
|
||||
<TextBlock Grid.Row="3" Text="E-MAIL" Style="{StaticResource RetroLabel}" VerticalAlignment="Center"/>
|
||||
<TextBox x:Name="EmailBox" Grid.Row="3" Grid.Column="1" Style="{StaticResource RetroTextBox}" Height="30"/>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,16,0,0">
|
||||
<TextBlock x:Name="ErrorText" Foreground="#C0392B" FontFamily="Courier New" FontSize="11"
|
||||
VerticalAlignment="Center" Margin="0,0,12,0"/>
|
||||
<Button Content="[ ABBRECHEN ]" Style="{StaticResource RetroButtonGray}" Height="32"
|
||||
Click="CancelClick" Margin="0,0,8,0"/>
|
||||
<Button Content="[ SPEICHERN ]" Style="{StaticResource RetroButtonGreen}" Height="32"
|
||||
Click="SaveClick"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
58
Views/UserEditDialog.xaml.cs
Normal file
58
Views/UserEditDialog.xaml.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using CineBook.Models;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace CineBook.Views;
|
||||
|
||||
public partial class UserEditDialog : Window
|
||||
{
|
||||
public string Username { get; private set; } = "";
|
||||
public string Password { get; private set; } = "";
|
||||
public string Role { get; private set; } = "User";
|
||||
public string Email { get; private set; } = "";
|
||||
|
||||
private readonly User? _editing;
|
||||
|
||||
public UserEditDialog(User? user)
|
||||
{
|
||||
InitializeComponent();
|
||||
_editing = user;
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
DialogTitle.Text = "👤 BENUTZER BEARBEITEN";
|
||||
UsernameBox.Text = user.Username;
|
||||
EmailBox.Text = user.Email;
|
||||
foreach (ComboBoxItem item in RoleBox.Items)
|
||||
if (item.Content?.ToString() == user.Role)
|
||||
RoleBox.SelectedItem = item;
|
||||
}
|
||||
else
|
||||
{
|
||||
DialogTitle.Text = "👤 BENUTZER ANLEGEN";
|
||||
RoleBox.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(UsernameBox.Text) || UsernameBox.Text.Trim().Length < 3)
|
||||
{ ErrorText.Text = "⚠ Benutzername mindestens 3 Zeichen!"; return; }
|
||||
|
||||
if (_editing == null && (string.IsNullOrEmpty(PasswordBox.Password) || PasswordBox.Password.Length < 6))
|
||||
{ ErrorText.Text = "⚠ Passwort mindestens 6 Zeichen!"; return; }
|
||||
|
||||
if (RoleBox.SelectedItem is not ComboBoxItem ri)
|
||||
{ ErrorText.Text = "⚠ Rolle auswählen!"; return; }
|
||||
|
||||
Username = UsernameBox.Text.Trim();
|
||||
Password = PasswordBox.Password;
|
||||
Role = ri.Content?.ToString() ?? "User";
|
||||
Email = EmailBox.Text.Trim();
|
||||
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
|
||||
private void CancelClick(object sender, RoutedEventArgs e) { DialogResult = false; Close(); }
|
||||
}
|
||||
Reference in New Issue
Block a user