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.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
@ -9,7 +250,8 @@ 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).
/// View-only display of meal schedules from production.
/// Loads all schedules on open; optional Site filter.
/// </summary>
public partial class MealSchedulesViewModel : ObservableObject
{
@ -19,7 +261,6 @@ public partial class MealSchedulesViewModel : ObservableObject
[ObservableProperty]
private ObservableCollection<MealSchedule> _schedules = new();
/// <summary>Full list from production; Schedules is filtered by SelectedSiteFilter.</summary>
private List<MealSchedule> _allSchedules = new();
[ObservableProperty]
@ -31,18 +272,6 @@ public partial class MealSchedulesViewModel : ObservableObject
[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;
@ -64,23 +293,21 @@ public partial class MealSchedulesViewModel : ObservableObject
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")
if (string.IsNullOrWhiteSpace(SelectedSiteFilter) || SelectedSiteFilter == "All")
{
Schedules = new ObservableCollection<MealSchedule>(_allSchedules);
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);
}
@ -89,24 +316,35 @@ public partial class MealSchedulesViewModel : ObservableObject
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();
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).";
Message = "No schedules 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.";
Message = "Could not load schedules.";
MessageBox.Show(msg, "Meal Schedules Load Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
@ -115,124 +353,9 @@ 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]
private void Back()
{
_navigation.NavigateToSettings();
}
}
}

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:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:UtopiaCanteenSystem.Converters">
<UserControl.Resources>
<converters:MealSessionToNameConverter x:Key="MealSessionConverter"/>
<!-- Palette -->
--><!-- Palette --><!--
<SolidColorBrush x:Key="PrimaryText" Color="#1F2933"/>
<SolidColorBrush x:Key="MutedText" Color="#718096"/>
<SolidColorBrush x:Key="PrimaryAccent" Color="#5BA3A0"/>
@ -14,7 +14,7 @@
<SolidColorBrush x:Key="ErrorBrush" Color="#E53E3E"/>
<SolidColorBrush x:Key="CardBackground" Color="#FFFFFF"/>
<!-- Card style -->
--><!-- Card style --><!--
<Style x:Key="CardBorder" TargetType="Border">
<Setter Property="Background" Value="{StaticResource CardBackground}"/>
<Setter Property="CornerRadius" Value="16"/>
@ -33,7 +33,7 @@
</Setter>
</Style>
<!-- Buttons -->
--><!-- Buttons --><!--
<Style x:Key="PrimaryButton" TargetType="Button">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="{StaticResource PrimaryAccent}"/>
@ -88,7 +88,7 @@
<Setter Property="Background" Value="#FFF5F5"/>
</Style>
<!-- Back button: pill style with hover/pressed -->
--><!-- Back button: pill style with hover/pressed --><!--
<Style x:Key="BackButton" TargetType="Button" BasedOn="{StaticResource SecondaryButton}">
<Setter Property="Padding" Value="18,10"/>
<Setter Property="MinWidth" Value="100"/>
@ -130,7 +130,7 @@
</Setter>
</Style>
<!-- Small icon action buttons for DataGrid Actions column -->
--><!-- Small icon action buttons for DataGrid Actions column --><!--
<Style x:Key="GridActionButton" TargetType="Button">
<Setter Property="Width" Value="28"/>
<Setter Property="Height" Value="28"/>
@ -169,7 +169,7 @@
<Setter Property="ToolTip" Value="Delete"/>
</Style>
<!-- Inputs -->
--><!-- Inputs --><!--
<Style x:Key="ModernTextBox" TargetType="TextBox">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="10,8"/>
@ -192,7 +192,7 @@
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<!-- DataGrid styling -->
--><!-- DataGrid styling --><!--
<Style x:Key="ModernDataGrid" TargetType="DataGrid">
<Setter Property="AutoGenerateColumns" Value="False"/>
<Setter Property="CanUserAddRows" Value="False"/>
@ -276,7 +276,7 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- HEADER BAR -->
--><!-- HEADER BAR --><!--
<Grid Grid.Row="0" Margin="24,20,24,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
@ -285,25 +285,25 @@
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Back -->
--><!-- Back --><!--
<Button Grid.Column="0"
Command="{Binding BackCommand}"
Style="{StaticResource BackButton}"
Content="Back"/>
<!-- Title + subtitle -->
--><!-- Title + subtitle --><!--
<StackPanel Grid.Column="1" Margin="16,0,0,0" VerticalAlignment="Center">
<TextBlock Text="Meal Schedules"
FontSize="24"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryText}"/>
<!--<TextBlock Text="(production hrms.meal_schedule)"
--><!--<TextBlock Text="(production hrms.meal_schedule)"
FontSize="13"
Foreground="{StaticResource MutedText}"
Margin="0,2,0,0"/>-->
Margin="0,2,0,0"/>--><!--
</StackPanel>
<!-- Site filter -->
--><!-- Site filter --><!--
<StackPanel Grid.Column="2"
Orientation="Horizontal"
HorizontalAlignment="Right"
@ -320,7 +320,7 @@
Style="{StaticResource ModernComboBox}"/>
</StackPanel>
<!-- Add New -->
--><!-- Add New --><!--
<Button Grid.Column="3"
Command="{Binding AddNewCommand}"
Style="{StaticResource PrimaryButton}">
@ -331,12 +331,12 @@
</Button>
</Grid>
<!-- MAIN CONTENT -->
--><!-- MAIN CONTENT --><!--
<ScrollViewer Grid.Row="1"
Margin="24,0,24,16"
VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- Schedules card -->
--><!-- Schedules card --><!--
<Border Style="{StaticResource CardBorder}">
<Grid>
<Grid.RowDefinitions>
@ -344,7 +344,7 @@
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Card header -->
--><!-- Card header --><!--
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,12">
<StackPanel>
<TextBlock Text="Schedules"
@ -357,7 +357,7 @@
</StackPanel>
</StackPanel>
<!-- DataGrid -->
--><!-- DataGrid --><!--
<DataGrid Grid.Row="1"
Style="{StaticResource ModernDataGrid}"
ItemsSource="{Binding Schedules}"
@ -429,7 +429,7 @@
</Grid>
</Border>
<!-- Add / Edit card -->
--><!-- Add / Edit card --><!--
<Border Style="{StaticResource CardBorder}">
<Grid>
<Grid.RowDefinitions>
@ -438,7 +438,7 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Card header -->
--><!-- Card header --><!--
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,16">
<StackPanel>
<TextBlock Text="Add or Edit Meal Schedule"
@ -448,16 +448,16 @@
</StackPanel>
</StackPanel>
<!-- Form -->
--><!-- Form --><!--
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Left column -->
--><!-- Left column --><!--
<StackPanel Grid.Column="0" Margin="0,0,16,0">
<!-- Location Site ID -->
--><!-- Location Site ID --><!--
<StackPanel Margin="0,0,0,12">
<TextBlock Text="Location Site ID"
FontSize="12"
@ -467,7 +467,7 @@
Style="{StaticResource ModernTextBox}"/>
</StackPanel>
<!-- Meal Session -->
--><!-- Meal Session --><!--
<StackPanel Margin="0,0,0,12">
<TextBlock Text="Meal Session"
FontSize="12"
@ -478,9 +478,9 @@
</StackPanel>
</StackPanel>
<!-- Right column -->
--><!-- Right column --><!--
<StackPanel Grid.Column="1" Margin="0,0,0,0">
<!-- Start time -->
--><!-- Start time --><!--
<StackPanel Margin="0,0,0,12">
<TextBlock Text="Start (HH:mm:ss)"
FontSize="12"
@ -503,7 +503,7 @@
</Grid>
</StackPanel>
<!-- End time -->
--><!-- End time --><!--
<StackPanel Margin="0,0,0,12">
<TextBlock Text="End (HH:mm:ss)"
FontSize="12"
@ -528,7 +528,7 @@
</StackPanel>
</Grid>
<!-- Buttons -->
--><!-- Buttons --><!--
<StackPanel Grid.Row="2"
Orientation="Horizontal"
HorizontalAlignment="Right"
@ -550,7 +550,7 @@
</StackPanel>
</ScrollViewer>
<!-- Message -->
--><!-- Message --><!--
<Border Grid.Row="2"
Margin="24,0,24,20"
Background="Transparent">
@ -572,4 +572,181 @@
</TextBlock>
</Border>
</Grid>
</UserControl>
</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>