make the meal schedule page view only

pull/1/head
SYED MUSTUFA AHMED NAQVI 2026-03-10 13:56:31 +05:00
parent 4d2433fa28
commit dcf536f0c7
2 changed files with 475 additions and 175 deletions

View File

@ -1,3 +1,244 @@
//using System.Collections.ObjectModel;
//using System.Windows;
//using CommunityToolkit.Mvvm.ComponentModel;
//using CommunityToolkit.Mvvm.Input;
//using MySqlConnector;
//using UtopiaCanteenSystem.Models;
//using UtopiaCanteenSystem.Services;
//namespace UtopiaCanteenSystem.ViewModels;
///// <summary>
///// Admin CRUD for meal schedules in production (hrms.meal_schedule). No SQLite. Load all on open; optional Site filter (local).
///// </summary>
//public partial class MealSchedulesViewModel : ObservableObject
//{
// private readonly IMealScheduleService _mealScheduleService;
// private readonly INavigationService _navigation;
// [ObservableProperty]
// private ObservableCollection<MealSchedule> _schedules = new();
// /// <summary>Full list from production; Schedules is filtered by SelectedSiteFilter.</summary>
// private List<MealSchedule> _allSchedules = new();
// [ObservableProperty]
// private ObservableCollection<string> _siteFilterChoices = new() { "All" };
// [ObservableProperty]
// private string _selectedSiteFilter = "All";
// [ObservableProperty]
// private MealSchedule? _selectedSchedule;
// [ObservableProperty]
// private string _locationSiteId = string.Empty;
// [ObservableProperty]
// private string _mealName = string.Empty;
// [ObservableProperty]
// private string _startTime = "06:00:00";
// [ObservableProperty]
// private string _endTime = "09:00:00";
// [ObservableProperty]
// private string _message = string.Empty;
// [ObservableProperty]
// private bool _isError;
// [ObservableProperty]
// private bool _isLoading;
// public MealSchedulesViewModel(IMealScheduleService mealScheduleService, INavigationService navigation)
// {
// _mealScheduleService = mealScheduleService;
// _navigation = navigation;
// _ = LoadSchedulesAsync();
// }
// partial void OnSelectedSiteFilterChanged(string value)
// {
// ApplyFilter();
// }
// partial void OnSelectedScheduleChanged(MealSchedule? value)
// {
// if (value == null) return;
// LocationSiteId = value.LocationSiteId ?? string.Empty;
// MealName = value.MealName ?? string.Empty;
// StartTime = value.StartTime ?? "00:00:00";
// EndTime = value.EndTime ?? "23:59:59";
// }
// private void ApplyFilter()
// {
// if (string.IsNullOrEmpty(SelectedSiteFilter) || SelectedSiteFilter == "All")
// {
// Schedules = new ObservableCollection<MealSchedule>(_allSchedules);
// return;
// }
// var filtered = _allSchedules.Where(s => string.Equals(s.LocationSiteId?.Trim(), SelectedSiteFilter.Trim(), StringComparison.OrdinalIgnoreCase)).ToList();
// Schedules = new ObservableCollection<MealSchedule>(filtered);
// }
// private async Task LoadSchedulesAsync()
// {
// IsLoading = true;
// Message = string.Empty;
// IsError = false;
// try
// {
// var list = await _mealScheduleService.GetAllSchedulesAsync().ConfigureAwait(true);
// _allSchedules = list.ToList();
// var siteIds = _allSchedules.Select(s => s.LocationSiteId?.Trim() ?? "").Where(s => !string.IsNullOrEmpty(s)).Distinct().OrderBy(s => s, StringComparer.Ordinal).ToList();
// SiteFilterChoices = new ObservableCollection<string>(new[] { "All" }.Concat(siteIds));
// SelectedSiteFilter = "All";
// ApplyFilter();
// if (_allSchedules.Count == 0)
// Message = "No schedules in production. Add one below (HRMS MySQL must be configured).";
// }
// catch (Exception ex)
// {
// IsError = true;
// var msg = ex is MySqlException mysql
// ? $"{mysql.Message}{Environment.NewLine}{Environment.NewLine}{mysql.StackTrace}"
// : $"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}";
// Message = "Could not load schedules from production.";
// MessageBox.Show(msg, "Meal Schedules Load Error", MessageBoxButton.OK, MessageBoxImage.Error);
// }
// finally
// {
// IsLoading = false;
// }
// }
// [RelayCommand]
// private void AddNew()
// {
// SelectedSchedule = null;
// LocationSiteId = "02";
// MealName = string.Empty;
// StartTime = "06:00:00";
// EndTime = "09:00:00";
// Message = string.Empty;
// }
// [RelayCommand]
// private async Task Save()
// {
// Message = string.Empty;
// IsError = false;
// if (!TimeSpan.TryParse(StartTime?.Trim(), out var start) || !TimeSpan.TryParse(EndTime?.Trim(), out var end))
// {
// Message = "Start time and end time must be in HH:mm:ss format.";
// IsError = true;
// return;
// }
// if (start >= end)
// {
// Message = "Start time must be before end time.";
// IsError = true;
// return;
// }
// var siteId = (LocationSiteId ?? string.Empty).Trim();
// if (string.IsNullOrEmpty(siteId))
// {
// Message = "Location site ID is required.";
// IsError = true;
// return;
// }
// try
// {
// if (SelectedSchedule != null)
// {
// var dto = new MealSchedule
// {
// Id = SelectedSchedule.Id,
// MealName = (MealName ?? string.Empty).Trim(),
// LocationSiteId = siteId,
// StartTime = StartTime.Trim(),
// EndTime = EndTime.Trim()
// };
// await _mealScheduleService.UpdateAsync(dto).ConfigureAwait(true);
// Message = "Schedule updated in production.";
// }
// else
// {
// var dto = new MealSchedule
// {
// MealName = (MealName ?? string.Empty).Trim(),
// LocationSiteId = siteId,
// StartTime = StartTime.Trim(),
// EndTime = EndTime.Trim()
// };
// await _mealScheduleService.CreateAsync(dto).ConfigureAwait(true);
// Message = "Schedule added to production.";
// }
// await LoadSchedulesAsync().ConfigureAwait(true);
// }
// catch (Exception ex)
// {
// IsError = true;
// var msg = ex is MySqlException mysql
// ? $"{mysql.Message}{Environment.NewLine}{Environment.NewLine}{mysql.StackTrace}"
// : $"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}";
// Message = "Failed to save to production.";
// MessageBox.Show(msg, "Meal Schedules Save Error", MessageBoxButton.OK, MessageBoxImage.Error);
// }
// }
// /// <summary>Selects a schedule for editing (used by Actions column Edit button).</summary>
// [RelayCommand]
// private void SelectSchedule(MealSchedule? schedule)
// {
// SelectedSchedule = schedule;
// }
// [RelayCommand]
// private async Task Delete(MealSchedule? row)
// {
// var toDelete = row ?? SelectedSchedule;
// if (toDelete == null)
// {
// Message = "Select a schedule to delete.";
// IsError = true;
// return;
// }
// Message = string.Empty;
// IsError = false;
// try
// {
// await _mealScheduleService.DeleteAsync(toDelete.Id).ConfigureAwait(true);
// Message = "Schedule deleted from production.";
// SelectedSchedule = null;
// await LoadSchedulesAsync().ConfigureAwait(true);
// }
// catch (Exception ex)
// {
// IsError = true;
// var msg = ex is MySqlException mysql
// ? $"{mysql.Message}{Environment.NewLine}{Environment.NewLine}{mysql.StackTrace}"
// : $"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}";
// Message = "Failed to delete.";
// MessageBox.Show(msg, "Meal Schedules Delete Error", MessageBoxButton.OK, MessageBoxImage.Error);
// }
// }
// [RelayCommand]
// private void Back()
// {
// _navigation.NavigateToSettings();
// }
//}
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Windows; using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
@ -9,7 +250,8 @@ using UtopiaCanteenSystem.Services;
namespace UtopiaCanteenSystem.ViewModels; namespace UtopiaCanteenSystem.ViewModels;
/// <summary> /// <summary>
/// Admin CRUD for meal schedules in production (hrms.meal_schedule). No SQLite. Load all on open; optional Site filter (local). /// View-only display of meal schedules from production.
/// Loads all schedules on open; optional Site filter.
/// </summary> /// </summary>
public partial class MealSchedulesViewModel : ObservableObject public partial class MealSchedulesViewModel : ObservableObject
{ {
@ -19,7 +261,6 @@ public partial class MealSchedulesViewModel : ObservableObject
[ObservableProperty] [ObservableProperty]
private ObservableCollection<MealSchedule> _schedules = new(); private ObservableCollection<MealSchedule> _schedules = new();
/// <summary>Full list from production; Schedules is filtered by SelectedSiteFilter.</summary>
private List<MealSchedule> _allSchedules = new(); private List<MealSchedule> _allSchedules = new();
[ObservableProperty] [ObservableProperty]
@ -31,18 +272,6 @@ public partial class MealSchedulesViewModel : ObservableObject
[ObservableProperty] [ObservableProperty]
private MealSchedule? _selectedSchedule; private MealSchedule? _selectedSchedule;
[ObservableProperty]
private string _locationSiteId = string.Empty;
[ObservableProperty]
private string _mealName = string.Empty;
[ObservableProperty]
private string _startTime = "06:00:00";
[ObservableProperty]
private string _endTime = "09:00:00";
[ObservableProperty] [ObservableProperty]
private string _message = string.Empty; private string _message = string.Empty;
@ -64,23 +293,21 @@ public partial class MealSchedulesViewModel : ObservableObject
ApplyFilter(); ApplyFilter();
} }
partial void OnSelectedScheduleChanged(MealSchedule? value)
{
if (value == null) return;
LocationSiteId = value.LocationSiteId ?? string.Empty;
MealName = value.MealName ?? string.Empty;
StartTime = value.StartTime ?? "00:00:00";
EndTime = value.EndTime ?? "23:59:59";
}
private void ApplyFilter() private void ApplyFilter()
{ {
if (string.IsNullOrEmpty(SelectedSiteFilter) || SelectedSiteFilter == "All") if (string.IsNullOrWhiteSpace(SelectedSiteFilter) || SelectedSiteFilter == "All")
{ {
Schedules = new ObservableCollection<MealSchedule>(_allSchedules); Schedules = new ObservableCollection<MealSchedule>(_allSchedules);
return; return;
} }
var filtered = _allSchedules.Where(s => string.Equals(s.LocationSiteId?.Trim(), SelectedSiteFilter.Trim(), StringComparison.OrdinalIgnoreCase)).ToList();
var filtered = _allSchedules
.Where(s => string.Equals(
s.LocationSiteId?.Trim(),
SelectedSiteFilter.Trim(),
StringComparison.OrdinalIgnoreCase))
.ToList();
Schedules = new ObservableCollection<MealSchedule>(filtered); Schedules = new ObservableCollection<MealSchedule>(filtered);
} }
@ -89,24 +316,35 @@ public partial class MealSchedulesViewModel : ObservableObject
IsLoading = true; IsLoading = true;
Message = string.Empty; Message = string.Empty;
IsError = false; IsError = false;
try try
{ {
var list = await _mealScheduleService.GetAllSchedulesAsync().ConfigureAwait(true); var list = await _mealScheduleService.GetAllSchedulesAsync().ConfigureAwait(true);
_allSchedules = list.ToList(); _allSchedules = list.ToList();
var siteIds = _allSchedules.Select(s => s.LocationSiteId?.Trim() ?? "").Where(s => !string.IsNullOrEmpty(s)).Distinct().OrderBy(s => s, StringComparer.Ordinal).ToList();
var siteIds = _allSchedules
.Select(s => s.LocationSiteId?.Trim() ?? "")
.Where(s => !string.IsNullOrEmpty(s))
.Distinct()
.OrderBy(s => s, StringComparer.Ordinal)
.ToList();
SiteFilterChoices = new ObservableCollection<string>(new[] { "All" }.Concat(siteIds)); SiteFilterChoices = new ObservableCollection<string>(new[] { "All" }.Concat(siteIds));
SelectedSiteFilter = "All"; SelectedSiteFilter = "All";
ApplyFilter(); ApplyFilter();
if (_allSchedules.Count == 0) if (_allSchedules.Count == 0)
Message = "No schedules in production. Add one below (HRMS MySQL must be configured)."; Message = "No schedules configured.";
} }
catch (Exception ex) catch (Exception ex)
{ {
IsError = true; IsError = true;
var msg = ex is MySqlException mysql var msg = ex is MySqlException mysql
? $"{mysql.Message}{Environment.NewLine}{Environment.NewLine}{mysql.StackTrace}" ? $"{mysql.Message}{Environment.NewLine}{Environment.NewLine}{mysql.StackTrace}"
: $"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}"; : $"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}";
Message = "Could not load schedules from production.";
Message = "Could not load schedules.";
MessageBox.Show(msg, "Meal Schedules Load Error", MessageBoxButton.OK, MessageBoxImage.Error); MessageBox.Show(msg, "Meal Schedules Load Error", MessageBoxButton.OK, MessageBoxImage.Error);
} }
finally finally
@ -115,121 +353,6 @@ public partial class MealSchedulesViewModel : ObservableObject
} }
} }
[RelayCommand]
private void AddNew()
{
SelectedSchedule = null;
LocationSiteId = "02";
MealName = string.Empty;
StartTime = "06:00:00";
EndTime = "09:00:00";
Message = string.Empty;
}
[RelayCommand]
private async Task Save()
{
Message = string.Empty;
IsError = false;
if (!TimeSpan.TryParse(StartTime?.Trim(), out var start) || !TimeSpan.TryParse(EndTime?.Trim(), out var end))
{
Message = "Start time and end time must be in HH:mm:ss format.";
IsError = true;
return;
}
if (start >= end)
{
Message = "Start time must be before end time.";
IsError = true;
return;
}
var siteId = (LocationSiteId ?? string.Empty).Trim();
if (string.IsNullOrEmpty(siteId))
{
Message = "Location site ID is required.";
IsError = true;
return;
}
try
{
if (SelectedSchedule != null)
{
var dto = new MealSchedule
{
Id = SelectedSchedule.Id,
MealName = (MealName ?? string.Empty).Trim(),
LocationSiteId = siteId,
StartTime = StartTime.Trim(),
EndTime = EndTime.Trim()
};
await _mealScheduleService.UpdateAsync(dto).ConfigureAwait(true);
Message = "Schedule updated in production.";
}
else
{
var dto = new MealSchedule
{
MealName = (MealName ?? string.Empty).Trim(),
LocationSiteId = siteId,
StartTime = StartTime.Trim(),
EndTime = EndTime.Trim()
};
await _mealScheduleService.CreateAsync(dto).ConfigureAwait(true);
Message = "Schedule added to production.";
}
await LoadSchedulesAsync().ConfigureAwait(true);
}
catch (Exception ex)
{
IsError = true;
var msg = ex is MySqlException mysql
? $"{mysql.Message}{Environment.NewLine}{Environment.NewLine}{mysql.StackTrace}"
: $"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}";
Message = "Failed to save to production.";
MessageBox.Show(msg, "Meal Schedules Save Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>Selects a schedule for editing (used by Actions column Edit button).</summary>
[RelayCommand]
private void SelectSchedule(MealSchedule? schedule)
{
SelectedSchedule = schedule;
}
[RelayCommand]
private async Task Delete(MealSchedule? row)
{
var toDelete = row ?? SelectedSchedule;
if (toDelete == null)
{
Message = "Select a schedule to delete.";
IsError = true;
return;
}
Message = string.Empty;
IsError = false;
try
{
await _mealScheduleService.DeleteAsync(toDelete.Id).ConfigureAwait(true);
Message = "Schedule deleted from production.";
SelectedSchedule = null;
await LoadSchedulesAsync().ConfigureAwait(true);
}
catch (Exception ex)
{
IsError = true;
var msg = ex is MySqlException mysql
? $"{mysql.Message}{Environment.NewLine}{Environment.NewLine}{mysql.StackTrace}"
: $"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}";
Message = "Failed to delete.";
MessageBox.Show(msg, "Meal Schedules Delete Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
[RelayCommand] [RelayCommand]
private void Back() private void Back()
{ {

View File

@ -1,11 +1,11 @@
<UserControl x:Class="UtopiaCanteenSystem.Views.MealSchedulesView" <!--<UserControl x:Class="UtopiaCanteenSystem.Views.MealSchedulesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:UtopiaCanteenSystem.Converters"> xmlns:converters="clr-namespace:UtopiaCanteenSystem.Converters">
<UserControl.Resources> <UserControl.Resources>
<converters:MealSessionToNameConverter x:Key="MealSessionConverter"/> <converters:MealSessionToNameConverter x:Key="MealSessionConverter"/>
<!-- Palette --> --><!-- Palette --><!--
<SolidColorBrush x:Key="PrimaryText" Color="#1F2933"/> <SolidColorBrush x:Key="PrimaryText" Color="#1F2933"/>
<SolidColorBrush x:Key="MutedText" Color="#718096"/> <SolidColorBrush x:Key="MutedText" Color="#718096"/>
<SolidColorBrush x:Key="PrimaryAccent" Color="#5BA3A0"/> <SolidColorBrush x:Key="PrimaryAccent" Color="#5BA3A0"/>
@ -14,7 +14,7 @@
<SolidColorBrush x:Key="ErrorBrush" Color="#E53E3E"/> <SolidColorBrush x:Key="ErrorBrush" Color="#E53E3E"/>
<SolidColorBrush x:Key="CardBackground" Color="#FFFFFF"/> <SolidColorBrush x:Key="CardBackground" Color="#FFFFFF"/>
<!-- Card style --> --><!-- Card style --><!--
<Style x:Key="CardBorder" TargetType="Border"> <Style x:Key="CardBorder" TargetType="Border">
<Setter Property="Background" Value="{StaticResource CardBackground}"/> <Setter Property="Background" Value="{StaticResource CardBackground}"/>
<Setter Property="CornerRadius" Value="16"/> <Setter Property="CornerRadius" Value="16"/>
@ -33,7 +33,7 @@
</Setter> </Setter>
</Style> </Style>
<!-- Buttons --> --><!-- Buttons --><!--
<Style x:Key="PrimaryButton" TargetType="Button"> <Style x:Key="PrimaryButton" TargetType="Button">
<Setter Property="Foreground" Value="White"/> <Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="{StaticResource PrimaryAccent}"/> <Setter Property="Background" Value="{StaticResource PrimaryAccent}"/>
@ -88,7 +88,7 @@
<Setter Property="Background" Value="#FFF5F5"/> <Setter Property="Background" Value="#FFF5F5"/>
</Style> </Style>
<!-- Back button: pill style with hover/pressed --> --><!-- Back button: pill style with hover/pressed --><!--
<Style x:Key="BackButton" TargetType="Button" BasedOn="{StaticResource SecondaryButton}"> <Style x:Key="BackButton" TargetType="Button" BasedOn="{StaticResource SecondaryButton}">
<Setter Property="Padding" Value="18,10"/> <Setter Property="Padding" Value="18,10"/>
<Setter Property="MinWidth" Value="100"/> <Setter Property="MinWidth" Value="100"/>
@ -130,7 +130,7 @@
</Setter> </Setter>
</Style> </Style>
<!-- Small icon action buttons for DataGrid Actions column --> --><!-- Small icon action buttons for DataGrid Actions column --><!--
<Style x:Key="GridActionButton" TargetType="Button"> <Style x:Key="GridActionButton" TargetType="Button">
<Setter Property="Width" Value="28"/> <Setter Property="Width" Value="28"/>
<Setter Property="Height" Value="28"/> <Setter Property="Height" Value="28"/>
@ -169,7 +169,7 @@
<Setter Property="ToolTip" Value="Delete"/> <Setter Property="ToolTip" Value="Delete"/>
</Style> </Style>
<!-- Inputs --> --><!-- Inputs --><!--
<Style x:Key="ModernTextBox" TargetType="TextBox"> <Style x:Key="ModernTextBox" TargetType="TextBox">
<Setter Property="Margin" Value="0"/> <Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="10,8"/> <Setter Property="Padding" Value="10,8"/>
@ -192,7 +192,7 @@
<Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="VerticalContentAlignment" Value="Center"/>
</Style> </Style>
<!-- DataGrid styling --> --><!-- DataGrid styling --><!--
<Style x:Key="ModernDataGrid" TargetType="DataGrid"> <Style x:Key="ModernDataGrid" TargetType="DataGrid">
<Setter Property="AutoGenerateColumns" Value="False"/> <Setter Property="AutoGenerateColumns" Value="False"/>
<Setter Property="CanUserAddRows" Value="False"/> <Setter Property="CanUserAddRows" Value="False"/>
@ -276,7 +276,7 @@
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- HEADER BAR --> --><!-- HEADER BAR --><!--
<Grid Grid.Row="0" Margin="24,20,24,16"> <Grid Grid.Row="0" Margin="24,20,24,16">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
@ -285,25 +285,25 @@
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<!-- Back --> --><!-- Back --><!--
<Button Grid.Column="0" <Button Grid.Column="0"
Command="{Binding BackCommand}" Command="{Binding BackCommand}"
Style="{StaticResource BackButton}" Style="{StaticResource BackButton}"
Content="Back"/> Content="Back"/>
<!-- Title + subtitle --> --><!-- Title + subtitle --><!--
<StackPanel Grid.Column="1" Margin="16,0,0,0" VerticalAlignment="Center"> <StackPanel Grid.Column="1" Margin="16,0,0,0" VerticalAlignment="Center">
<TextBlock Text="Meal Schedules" <TextBlock Text="Meal Schedules"
FontSize="24" FontSize="24"
FontWeight="SemiBold" FontWeight="SemiBold"
Foreground="{StaticResource PrimaryText}"/> Foreground="{StaticResource PrimaryText}"/>
<!--<TextBlock Text="(production hrms.meal_schedule)" --><!--<TextBlock Text="(production hrms.meal_schedule)"
FontSize="13" FontSize="13"
Foreground="{StaticResource MutedText}" Foreground="{StaticResource MutedText}"
Margin="0,2,0,0"/>--> Margin="0,2,0,0"/>--><!--
</StackPanel> </StackPanel>
<!-- Site filter --> --><!-- Site filter --><!--
<StackPanel Grid.Column="2" <StackPanel Grid.Column="2"
Orientation="Horizontal" Orientation="Horizontal"
HorizontalAlignment="Right" HorizontalAlignment="Right"
@ -320,7 +320,7 @@
Style="{StaticResource ModernComboBox}"/> Style="{StaticResource ModernComboBox}"/>
</StackPanel> </StackPanel>
<!-- Add New --> --><!-- Add New --><!--
<Button Grid.Column="3" <Button Grid.Column="3"
Command="{Binding AddNewCommand}" Command="{Binding AddNewCommand}"
Style="{StaticResource PrimaryButton}"> Style="{StaticResource PrimaryButton}">
@ -331,12 +331,12 @@
</Button> </Button>
</Grid> </Grid>
<!-- MAIN CONTENT --> --><!-- MAIN CONTENT --><!--
<ScrollViewer Grid.Row="1" <ScrollViewer Grid.Row="1"
Margin="24,0,24,16" Margin="24,0,24,16"
VerticalScrollBarVisibility="Auto"> VerticalScrollBarVisibility="Auto">
<StackPanel> <StackPanel>
<!-- Schedules card --> --><!-- Schedules card --><!--
<Border Style="{StaticResource CardBorder}"> <Border Style="{StaticResource CardBorder}">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@ -344,7 +344,7 @@
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- Card header --> --><!-- Card header --><!--
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,12"> <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,12">
<StackPanel> <StackPanel>
<TextBlock Text="Schedules" <TextBlock Text="Schedules"
@ -357,7 +357,7 @@
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<!-- DataGrid --> --><!-- DataGrid --><!--
<DataGrid Grid.Row="1" <DataGrid Grid.Row="1"
Style="{StaticResource ModernDataGrid}" Style="{StaticResource ModernDataGrid}"
ItemsSource="{Binding Schedules}" ItemsSource="{Binding Schedules}"
@ -429,7 +429,7 @@
</Grid> </Grid>
</Border> </Border>
<!-- Add / Edit card --> --><!-- Add / Edit card --><!--
<Border Style="{StaticResource CardBorder}"> <Border Style="{StaticResource CardBorder}">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
@ -438,7 +438,7 @@
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<!-- Card header --> --><!-- Card header --><!--
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,16"> <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,16">
<StackPanel> <StackPanel>
<TextBlock Text="Add or Edit Meal Schedule" <TextBlock Text="Add or Edit Meal Schedule"
@ -448,16 +448,16 @@
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<!-- Form --> --><!-- Form --><!--
<Grid Grid.Row="1"> <Grid Grid.Row="1">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<!-- Left column --> --><!-- Left column --><!--
<StackPanel Grid.Column="0" Margin="0,0,16,0"> <StackPanel Grid.Column="0" Margin="0,0,16,0">
<!-- Location Site ID --> --><!-- Location Site ID --><!--
<StackPanel Margin="0,0,0,12"> <StackPanel Margin="0,0,0,12">
<TextBlock Text="Location Site ID" <TextBlock Text="Location Site ID"
FontSize="12" FontSize="12"
@ -467,7 +467,7 @@
Style="{StaticResource ModernTextBox}"/> Style="{StaticResource ModernTextBox}"/>
</StackPanel> </StackPanel>
<!-- Meal Session --> --><!-- Meal Session --><!--
<StackPanel Margin="0,0,0,12"> <StackPanel Margin="0,0,0,12">
<TextBlock Text="Meal Session" <TextBlock Text="Meal Session"
FontSize="12" FontSize="12"
@ -478,9 +478,9 @@
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<!-- Right column --> --><!-- Right column --><!--
<StackPanel Grid.Column="1" Margin="0,0,0,0"> <StackPanel Grid.Column="1" Margin="0,0,0,0">
<!-- Start time --> --><!-- Start time --><!--
<StackPanel Margin="0,0,0,12"> <StackPanel Margin="0,0,0,12">
<TextBlock Text="Start (HH:mm:ss)" <TextBlock Text="Start (HH:mm:ss)"
FontSize="12" FontSize="12"
@ -503,7 +503,7 @@
</Grid> </Grid>
</StackPanel> </StackPanel>
<!-- End time --> --><!-- End time --><!--
<StackPanel Margin="0,0,0,12"> <StackPanel Margin="0,0,0,12">
<TextBlock Text="End (HH:mm:ss)" <TextBlock Text="End (HH:mm:ss)"
FontSize="12" FontSize="12"
@ -528,7 +528,7 @@
</StackPanel> </StackPanel>
</Grid> </Grid>
<!-- Buttons --> --><!-- Buttons --><!--
<StackPanel Grid.Row="2" <StackPanel Grid.Row="2"
Orientation="Horizontal" Orientation="Horizontal"
HorizontalAlignment="Right" HorizontalAlignment="Right"
@ -550,7 +550,7 @@
</StackPanel> </StackPanel>
</ScrollViewer> </ScrollViewer>
<!-- Message --> --><!-- Message --><!--
<Border Grid.Row="2" <Border Grid.Row="2"
Margin="24,0,24,20" Margin="24,0,24,20"
Background="Transparent"> Background="Transparent">
@ -572,4 +572,181 @@
</TextBlock> </TextBlock>
</Border> </Border>
</Grid> </Grid>
</UserControl>-->
<UserControl x:Class="UtopiaCanteenSystem.Views.MealSchedulesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:UtopiaCanteenSystem.Converters">
<UserControl.Resources>
<converters:MealSessionToNameConverter x:Key="MealSessionConverter"/>
<SolidColorBrush x:Key="PrimaryText" Color="#1F2933"/>
<SolidColorBrush x:Key="MutedText" Color="#718096"/>
<SolidColorBrush x:Key="PrimaryAccent" Color="#5BA3A0"/>
<SolidColorBrush x:Key="PrimaryAccentLight" Color="#E3F5F4"/>
<SolidColorBrush x:Key="BorderBrush" Color="#E2E8F0"/>
<SolidColorBrush x:Key="ErrorBrush" Color="#E53E3E"/>
<SolidColorBrush x:Key="CardBackground" Color="#FFFFFF"/>
<Style x:Key="CardBorder" TargetType="Border">
<Setter Property="Background" Value="{StaticResource CardBackground}"/>
<Setter Property="CornerRadius" Value="16"/>
<Setter Property="Padding" Value="20"/>
<Setter Property="Margin" Value="0,0,0,18"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
</Style>
<Style x:Key="SecondaryButton" TargetType="Button">
<Setter Property="Foreground" Value="{StaticResource PrimaryText}"/>
<Setter Property="Background" Value="#FFFFFF"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="16,9"/>
<Setter Property="MinHeight" Value="36"/>
<Setter Property="MinWidth" Value="100"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Cursor" Value="Hand"/>
</Style>
<Style x:Key="BackButton" TargetType="Button" BasedOn="{StaticResource SecondaryButton}">
<Setter Property="Padding" Value="18,10"/>
<Setter Property="MinWidth" Value="100"/>
</Style>
<Style x:Key="ModernComboBox" TargetType="ComboBox">
<Setter Property="Padding" Value="10,4"/>
<Setter Property="BorderBrush" Value="{StaticResource BorderBrush}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Background" Value="White"/>
<Setter Property="MinHeight" Value="34"/>
</Style>
<Style x:Key="ModernDataGrid" TargetType="DataGrid">
<Setter Property="AutoGenerateColumns" Value="False"/>
<Setter Property="CanUserAddRows" Value="False"/>
<Setter Property="CanUserDeleteRows" Value="False"/>
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="HeadersVisibility" Value="Column"/>
<Setter Property="GridLinesVisibility" Value="None"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="RowBackground" Value="White"/>
<Setter Property="AlternatingRowBackground" Value="#F7FAFC"/>
<Setter Property="RowHeight" Value="44"/>
<Setter Property="ColumnHeaderHeight" Value="44"/>
</Style>
</UserControl.Resources>
<Grid Background="#F4F7FB">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Header -->
<Grid Grid.Row="0" Margin="24,20,24,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Command="{Binding BackCommand}"
Style="{StaticResource BackButton}"
Content="← Back"/>
<StackPanel Grid.Column="1" Margin="16,0,0,0" VerticalAlignment="Center">
<TextBlock Text="Meal Schedules"
FontSize="24"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryText}"/>
</StackPanel>
<StackPanel Grid.Column="2"
Orientation="Horizontal"
HorizontalAlignment="Right"
VerticalAlignment="Center">
<TextBlock Text="Site"
VerticalAlignment="Center"
Margin="0,0,8,0"
Foreground="{StaticResource MutedText}"
FontSize="13"/>
<ComboBox ItemsSource="{Binding SiteFilterChoices}"
SelectedItem="{Binding SelectedSiteFilter, Mode=TwoWay}"
MinWidth="100"
Style="{StaticResource ModernComboBox}"/>
</StackPanel>
</Grid>
<!-- Content -->
<ScrollViewer Grid.Row="1"
Margin="24,0,24,16"
VerticalScrollBarVisibility="Auto">
<StackPanel>
<Border Style="{StaticResource CardBorder}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="0,0,0,12">
<TextBlock Text="Meal Schedules"
FontSize="16"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryText}"/>
<TextBlock Text="View-only mode - configured meal windows per site"
FontSize="12"
Foreground="{StaticResource MutedText}"/>
</StackPanel>
<DataGrid Grid.Row="1"
Style="{StaticResource ModernDataGrid}"
ItemsSource="{Binding Schedules}"
SelectedItem="{Binding SelectedSchedule, Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTextColumn Header="Site"
Binding="{Binding LocationSiteId}"
Width="*"/>
<DataGridTextColumn Header="Session"
Binding="{Binding MealName}"
Width="*"/>
<DataGridTextColumn Header="Start Time"
Binding="{Binding StartTime}"
Width="*"/>
<DataGridTextColumn Header="End Time"
Binding="{Binding EndTime}"
Width="*"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Border>
</StackPanel>
</ScrollViewer>
<!-- Message -->
<Border Grid.Row="2"
Margin="24,0,24,20"
Background="Transparent">
<TextBlock Text="{Binding Message}" FontSize="14">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource PrimaryText}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsError}" Value="True">
<Setter Property="Foreground" Value="{StaticResource ErrorBrush}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Message}" Value="">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Border>
</Grid>
</UserControl> </UserControl>