using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using UtopiaCanteenSystem.Services; namespace UtopiaCanteenSystem.ViewModels; /// /// ViewModel for SettingsView: editable API endpoint (UIND sync URL), save, load from config. /// public partial class SettingsViewModel : ObservableObject { private readonly IConfigService _configService; private readonly INavigationService _navigation; private readonly IAdminAuditService _adminAudit; private readonly ISyncService _syncService; [ObservableProperty] private string _syncApiEndpoint = string.Empty; [ObservableProperty] private string _scanIntervalDays = "0"; [ObservableProperty] private string _scanIntervalHours = "0"; [ObservableProperty] private string _scanIntervalMinutes = "1"; [ObservableProperty] private string _scanIntervalSeconds = "0"; [ObservableProperty] private string _adminCardId = "ADMIN"; [ObservableProperty] private string _saveMessage = string.Empty; [ObservableProperty] private bool _isError; [ObservableProperty] private bool _isSaving; [ObservableProperty] private bool _isPosting; public bool CanPostNow => !IsPosting; public string PostButtonText => IsPosting ? "Posting..." : "Post Data"; partial void OnIsPostingChanged(bool value) { OnPropertyChanged(nameof(PostButtonText)); OnPropertyChanged(nameof(CanPostNow)); } public SettingsViewModel( IConfigService configService, INavigationService navigation, IAdminAuditService adminAudit, ISyncService syncService) { _configService = configService; _navigation = navigation; _adminAudit = adminAudit; _syncService = syncService; LoadFromConfig(); } /// Loads config from service. public void LoadFromConfig() { SyncApiEndpoint = _configService.GetSyncApiEndpoint(); ScanIntervalDays = _configService.GetScanIntervalDays().ToString(); ScanIntervalHours = _configService.GetScanIntervalHours().ToString(); ScanIntervalMinutes = _configService.GetScanIntervalMinutes().ToString(); ScanIntervalSeconds = _configService.GetScanIntervalSeconds().ToString(); // Always prefer the latest admin login from the database. var last = _adminAudit.GetLastLogin(); if (last != null && !string.IsNullOrWhiteSpace(last.EmployeeId)) AdminCardId = last.EmployeeId; else AdminCardId = "ADMIN"; } [RelayCommand] private void Save() { IsSaving = true; if (!int.TryParse(ScanIntervalDays, out var days) || days < 0 || days > 365) { SaveMessage = "Scan interval Days must be 0–365."; IsError = true; IsSaving = false; return; } if (!int.TryParse(ScanIntervalHours, out var hours) || hours < 0 || hours > 23) { SaveMessage = "Scan interval Hours must be 0–23."; IsError = true; IsSaving = false; return; } if (!int.TryParse(ScanIntervalMinutes, out var minutes) || minutes < 0 || minutes > 59) { SaveMessage = "Scan interval Minutes must be 0–59."; IsError = true; IsSaving = false; return; } if (!int.TryParse(ScanIntervalSeconds, out var seconds) || seconds < 0 || seconds > 59) { SaveMessage = "Scan interval Seconds must be 0–59."; IsError = true; IsSaving = false; return; } if (days == 0 && hours == 0 && minutes == 0 && seconds == 0) { SaveMessage = "Scan interval cannot be zero. Use at least 1 second."; IsError = true; IsSaving = false; return; } _configService.SetSyncApiEndpoint(SyncApiEndpoint?.Trim() ?? string.Empty); _configService.SetScanIntervalDays(days); _configService.SetScanIntervalHours(hours); _configService.SetScanIntervalMinutes(minutes); _configService.SetScanIntervalSeconds(seconds); _configService.SetAdminCardId(AdminCardId?.Trim() ?? string.Empty); SaveMessage = "Settings saved."; IsError = false; IsSaving = false; } [RelayCommand] private void Back() { _navigation.NavigateBackFromSettings(GetDashboardTimeout()); } /// Opens Meal Schedules admin screen (Phase 2.5). [RelayCommand] private void OpenMealSchedules() { _navigation.NavigateToMealSchedules(); } [RelayCommand] private async Task PostDataNow() { if (IsPosting) return; SaveMessage = string.Empty; IsError = false; IsPosting = true; try { // If not configured, do not attempt sync. if (string.IsNullOrWhiteSpace(_configService.GetMySqlConnectionString())) { SaveMessage = "MySQL connection string not configured."; IsError = true; return; } await _syncService.SyncNowAsync().ConfigureAwait(false); SaveMessage = "Posted data to production."; IsError = false; } catch { SaveMessage = "Failed to post data to production."; IsError = true; } finally { IsPosting = false; } } private TimeSpan GetDashboardTimeout() => _configService.GetScanInterval(); }