233 lines
7.7 KiB
C#
233 lines
7.7 KiB
C#
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 int _mealSessionIndex; // 0=Breakfast, 1=Lunch, 2=Tea, 3=Dinner
|
||
|
||
[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 static readonly string[] MealSessionNames = { "Breakfast", "Lunch", "Tea", "Dinner" };
|
||
|
||
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;
|
||
MealSessionIndex = value.MealSession;
|
||
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";
|
||
MealSessionIndex = 0;
|
||
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,
|
||
LocationSiteId = siteId,
|
||
MealSession = MealSessionIndex,
|
||
StartTime = StartTime.Trim(),
|
||
EndTime = EndTime.Trim()
|
||
};
|
||
await _mealScheduleService.UpdateAsync(dto).ConfigureAwait(true);
|
||
Message = "Schedule updated in production.";
|
||
}
|
||
else
|
||
{
|
||
var dto = new MealSchedule
|
||
{
|
||
LocationSiteId = siteId,
|
||
MealSession = MealSessionIndex,
|
||
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);
|
||
}
|
||
}
|
||
|
||
[RelayCommand]
|
||
private async Task Delete()
|
||
{
|
||
if (SelectedSchedule == null)
|
||
{
|
||
Message = "Select a schedule to delete.";
|
||
IsError = true;
|
||
return;
|
||
}
|
||
Message = string.Empty;
|
||
IsError = false;
|
||
try
|
||
{
|
||
await _mealScheduleService.DeleteAsync(SelectedSchedule.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();
|
||
}
|
||
}
|