mirror of
https://github.com/claunia/marechai.git
synced 2026-07-08 17:57:08 +00:00
862 lines
33 KiB
C#
862 lines
33 KiB
C#
#nullable enable
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Marechai.ApiClient.Models;
|
|
using Marechai.App.Services;
|
|
using Marechai.App.Services.Authentication;
|
|
|
|
namespace Marechai.App.Presentation.ViewModels.Admin;
|
|
|
|
public partial class AdminMagazinesViewModel : ObservableObject, IRegionAware
|
|
{
|
|
private readonly Client _apiClient;
|
|
private readonly MagazinesService _magazinesService;
|
|
private readonly IJwtService _jwtService;
|
|
private readonly IStringLocalizer _localizer;
|
|
private readonly ILogger<AdminMagazinesViewModel> _logger;
|
|
private readonly ITokenService _tokenService;
|
|
|
|
// --- List state ---
|
|
[ObservableProperty] private ObservableCollection<MagazineDto> _magazines = [];
|
|
[ObservableProperty] private ObservableCollection<MagazineDto> _filteredMagazines = [];
|
|
[ObservableProperty] private string _filterText = string.Empty;
|
|
[ObservableProperty] private MagazineDto? _selectedMagazine;
|
|
private List<MagazineDto>? _allMagazines;
|
|
|
|
[ObservableProperty] private bool _isLoading;
|
|
[ObservableProperty] private bool _isDataLoaded;
|
|
[ObservableProperty] private bool _hasError;
|
|
[ObservableProperty] private string _errorMessage = string.Empty;
|
|
[ObservableProperty] private bool _isAdmin;
|
|
|
|
// --- Edit panel state ---
|
|
[ObservableProperty] private bool _isEditing;
|
|
[ObservableProperty] private bool _isEditingExisting;
|
|
[ObservableProperty] private string _editPanelTitle = string.Empty;
|
|
private long? _editingMagazineId;
|
|
|
|
// --- Form fields ---
|
|
[ObservableProperty] private string _magazineTitle = string.Empty;
|
|
[ObservableProperty] private string _nativeTitle = string.Empty;
|
|
[ObservableProperty] private string _sortTitle = string.Empty;
|
|
[ObservableProperty] private string _issn = string.Empty;
|
|
[ObservableProperty] private DateTimeOffset? _published;
|
|
[ObservableProperty] private int _publishedPrecision;
|
|
[ObservableProperty] private DateTimeOffset? _firstPublication;
|
|
[ObservableProperty] private int _firstPublicationPrecision;
|
|
[ObservableProperty] private Iso31661NumericDto? _selectedCountry;
|
|
|
|
// --- Synopsis panel state ---
|
|
[ObservableProperty] private bool _isEditingSynopsis;
|
|
[ObservableProperty] private string _synopsisText = string.Empty;
|
|
[ObservableProperty] private long? _synopsisMagazineId;
|
|
[ObservableProperty] private ObservableCollection<LanguageItem> _availableLanguages = [];
|
|
[ObservableProperty] private LanguageItem? _selectedLanguage;
|
|
[ObservableProperty] private ObservableCollection<DocumentSynopsisDto> _existingSynopses = [];
|
|
|
|
// --- Picker data ---
|
|
[ObservableProperty] private ObservableCollection<Iso31661NumericDto> _countries = [];
|
|
|
|
// --- People junction ---
|
|
[ObservableProperty] private ObservableCollection<PersonByMagazineDto> _magazinePeople = [];
|
|
[ObservableProperty] private ObservableCollection<string> _magazinePeopleDisplays = [];
|
|
[ObservableProperty] private ObservableCollection<PersonDto> _availablePeople = [];
|
|
[ObservableProperty] private PersonDto? _selectedAvailablePerson;
|
|
[ObservableProperty] private ObservableCollection<DocumentRoleDto> _availableRoles = [];
|
|
[ObservableProperty] private DocumentRoleDto? _selectedPersonRole;
|
|
private List<PersonDto>? _allPeopleList;
|
|
|
|
// --- Companies junction ---
|
|
[ObservableProperty] private ObservableCollection<CompanyByMagazineDto> _magazineCompanies = [];
|
|
[ObservableProperty] private ObservableCollection<string> _magazineCompanyDisplays = [];
|
|
[ObservableProperty] private ObservableCollection<CompanyDto> _availableCompanies = [];
|
|
[ObservableProperty] private CompanyDto? _selectedAvailableCompany;
|
|
[ObservableProperty] private DocumentRoleDto? _selectedCompanyRole;
|
|
private List<CompanyDto>? _allCompaniesList;
|
|
|
|
// --- Machines junction ---
|
|
[ObservableProperty] private ObservableCollection<MagazineByMachineDto> _magazineMachines = [];
|
|
[ObservableProperty] private ObservableCollection<string> _magazineMachineDisplays = [];
|
|
[ObservableProperty] private ObservableCollection<MachineDto> _availableMachines = [];
|
|
[ObservableProperty] private MachineDto? _selectedAvailableMachine;
|
|
private List<MachineDto>? _allMachinesList;
|
|
|
|
// --- Machine Families junction ---
|
|
[ObservableProperty] private ObservableCollection<MagazineByMachineFamilyDto> _magazineMachineFamilies = [];
|
|
[ObservableProperty] private ObservableCollection<string> _magazineMachineFamilyDisplays = [];
|
|
[ObservableProperty] private ObservableCollection<MachineFamilyDto> _availableMachineFamilies = [];
|
|
[ObservableProperty] private MachineFamilyDto? _selectedAvailableMachineFamily;
|
|
private List<MachineFamilyDto>? _allMachineFamiliesList;
|
|
|
|
// --- Document roles ---
|
|
private List<DocumentRoleDto>? _allRolesList;
|
|
|
|
public AdminMagazinesViewModel(Client apiClient,
|
|
MagazinesService magazinesService,
|
|
IJwtService jwtService,
|
|
ITokenService tokenService,
|
|
ILogger<AdminMagazinesViewModel> logger,
|
|
IStringLocalizer localizer)
|
|
{
|
|
_apiClient = apiClient;
|
|
_magazinesService = magazinesService;
|
|
_jwtService = jwtService;
|
|
_tokenService = tokenService;
|
|
_logger = logger;
|
|
_localizer = localizer;
|
|
|
|
LoadMagazinesCommand = new AsyncRelayCommand(LoadMagazinesAsync);
|
|
OpenAddMagazineCommand = new RelayCommand(OpenAddMagazine);
|
|
OpenEditMagazineCommand = new RelayCommand<MagazineDto>(OpenEditMagazine);
|
|
DeleteMagazineCommand = new AsyncRelayCommand<MagazineDto>(DeleteMagazineAsync);
|
|
SaveMagazineCommand = new AsyncRelayCommand(SaveMagazineAsync);
|
|
CancelEditCommand = new RelayCommand(CancelEdit);
|
|
|
|
// Synopsis commands
|
|
OpenSynopsisCommand = new AsyncRelayCommand<MagazineDto>(OpenSynopsisAsync);
|
|
SaveSynopsisCommand = new AsyncRelayCommand(SaveSynopsisAsync);
|
|
CancelSynopsisCommand = new RelayCommand(CancelSynopsis);
|
|
DeleteSynopsisCommand = new AsyncRelayCommand<DocumentSynopsisDto>(DeleteSynopsisAsync);
|
|
EditSynopsisCommand = new RelayCommand<DocumentSynopsisDto>(EditSynopsis);
|
|
|
|
// Junction commands
|
|
AddPersonCommand = new AsyncRelayCommand(AddPersonAsync);
|
|
RemovePersonCommand = new AsyncRelayCommand<string>(RemovePersonByDisplayAsync);
|
|
AddCompanyCommand = new AsyncRelayCommand(AddCompanyAsync);
|
|
RemoveCompanyCommand = new AsyncRelayCommand<string>(RemoveCompanyByDisplayAsync);
|
|
AddMachineCommand = new AsyncRelayCommand(AddMachineAsync);
|
|
RemoveMachineCommand = new AsyncRelayCommand<string>(RemoveMachineByDisplayAsync);
|
|
AddMachineFamilyCommand = new AsyncRelayCommand(AddMachineFamilyAsync);
|
|
RemoveMachineFamilyCommand = new AsyncRelayCommand<string>(RemoveMachineFamilyByDisplayAsync);
|
|
|
|
InitializeLanguages();
|
|
CheckAdminRole();
|
|
}
|
|
|
|
// --- Commands ---
|
|
public IAsyncRelayCommand LoadMagazinesCommand { get; }
|
|
public IRelayCommand OpenAddMagazineCommand { get; }
|
|
public IRelayCommand<MagazineDto> OpenEditMagazineCommand { get; }
|
|
public IAsyncRelayCommand<MagazineDto> DeleteMagazineCommand { get; }
|
|
public IAsyncRelayCommand SaveMagazineCommand { get; }
|
|
public IRelayCommand CancelEditCommand { get; }
|
|
|
|
public IAsyncRelayCommand<MagazineDto> OpenSynopsisCommand { get; }
|
|
public IAsyncRelayCommand SaveSynopsisCommand { get; }
|
|
public IRelayCommand CancelSynopsisCommand { get; }
|
|
public IAsyncRelayCommand<DocumentSynopsisDto> DeleteSynopsisCommand { get; }
|
|
public IRelayCommand<DocumentSynopsisDto> EditSynopsisCommand { get; }
|
|
|
|
public IAsyncRelayCommand AddPersonCommand { get; }
|
|
public IAsyncRelayCommand<string> RemovePersonCommand { get; }
|
|
public IAsyncRelayCommand AddCompanyCommand { get; }
|
|
public IAsyncRelayCommand<string> RemoveCompanyCommand { get; }
|
|
public IAsyncRelayCommand AddMachineCommand { get; }
|
|
public IAsyncRelayCommand<string> RemoveMachineCommand { get; }
|
|
public IAsyncRelayCommand AddMachineFamilyCommand { get; }
|
|
public IAsyncRelayCommand<string> RemoveMachineFamilyCommand { get; }
|
|
|
|
// --- IRegionAware ---
|
|
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
|
|
public void OnNavigatedFrom(NavigationContext navigationContext) { }
|
|
|
|
public void OnNavigatedTo(NavigationContext navigationContext)
|
|
{
|
|
CheckAdminRole();
|
|
if(IsAdmin)
|
|
{
|
|
_ = LoadMagazinesCommand.ExecuteAsync(null);
|
|
_ = LoadPickerDataAsync();
|
|
}
|
|
}
|
|
|
|
// --- Role check ---
|
|
private void CheckAdminRole()
|
|
{
|
|
try
|
|
{
|
|
string token = _tokenService.GetToken();
|
|
if(string.IsNullOrWhiteSpace(token)) { IsAdmin = false; return; }
|
|
IEnumerable<string> roles = _jwtService.GetRoles(token);
|
|
IsAdmin = roles.Contains("Uberadmin", StringComparer.OrdinalIgnoreCase) ||
|
|
roles.Contains("Admin", StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
catch { IsAdmin = false; }
|
|
}
|
|
|
|
// --- Load magazines ---
|
|
private async Task LoadMagazinesAsync()
|
|
{
|
|
try
|
|
{
|
|
IsLoading = true; HasError = false; ErrorMessage = string.Empty;
|
|
Magazines.Clear();
|
|
List<MagazineDto> response = await _magazinesService.GetAllMagazinesAsync();
|
|
_allMagazines = response;
|
|
foreach(MagazineDto m in response) Magazines.Add(m);
|
|
ApplyFilter();
|
|
IsDataLoaded = true;
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error loading magazines");
|
|
ErrorMessage = _localizer["FailedToLoadMagazines"];
|
|
HasError = true;
|
|
}
|
|
finally { IsLoading = false; }
|
|
}
|
|
|
|
// --- Add magazine ---
|
|
private void OpenAddMagazine()
|
|
{
|
|
_editingMagazineId = null;
|
|
EditPanelTitle = _localizer["AddMagazineDialog_Title"];
|
|
ClearForm();
|
|
IsEditingExisting = false;
|
|
IsEditingSynopsis = false;
|
|
IsEditing = true;
|
|
}
|
|
|
|
// --- Edit magazine ---
|
|
private async void OpenEditMagazine(MagazineDto? magazine)
|
|
{
|
|
if(magazine?.Id == null) return;
|
|
|
|
try
|
|
{
|
|
MagazineDto? full = await _magazinesService.GetMagazineAsync(magazine.Id.Value);
|
|
if(full == null) return;
|
|
|
|
_editingMagazineId = magazine.Id;
|
|
EditPanelTitle = _localizer["EditMagazineDialog_Title"];
|
|
PopulateForm(full);
|
|
await LoadAllJunctionsAsync(magazine.Id.Value);
|
|
IsEditingExisting = true;
|
|
IsEditingSynopsis = false;
|
|
IsEditing = true;
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error loading magazine {Id}", magazine.Id);
|
|
ErrorMessage = _localizer["FailedToLoadMagazines"];
|
|
HasError = true;
|
|
}
|
|
}
|
|
|
|
// --- Delete magazine ---
|
|
private async Task DeleteMagazineAsync(MagazineDto? magazine)
|
|
{
|
|
if(magazine?.Id == null) return;
|
|
|
|
try
|
|
{
|
|
await _magazinesService.DeleteMagazineAsync(magazine.Id.Value);
|
|
await LoadMagazinesAsync();
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error deleting magazine {Id}", magazine.Id);
|
|
ErrorMessage = _localizer["FailedToDeleteMagazine"];
|
|
HasError = true;
|
|
}
|
|
}
|
|
|
|
// --- Save magazine ---
|
|
private async Task SaveMagazineAsync()
|
|
{
|
|
try
|
|
{
|
|
if(string.IsNullOrWhiteSpace(MagazineTitle))
|
|
{
|
|
ErrorMessage = _localizer["MagazineTitleRequired"];
|
|
HasError = true;
|
|
return;
|
|
}
|
|
|
|
var dto = new MagazineDto
|
|
{
|
|
Title = MagazineTitle,
|
|
NativeTitle = string.IsNullOrWhiteSpace(NativeTitle) ? null : NativeTitle,
|
|
SortTitle = string.IsNullOrWhiteSpace(SortTitle) ? null : SortTitle,
|
|
Issn = string.IsNullOrWhiteSpace(Issn) ? null : Issn,
|
|
Published = Published,
|
|
PublishedPrecision = PublishedPrecision,
|
|
FirstPublication = FirstPublication,
|
|
FirstPublicationPrecision = FirstPublicationPrecision,
|
|
CountryId = SelectedCountry?.Id
|
|
};
|
|
|
|
if(_editingMagazineId == null)
|
|
await _magazinesService.CreateMagazineAsync(dto);
|
|
else
|
|
{
|
|
dto.Id = _editingMagazineId;
|
|
await _magazinesService.UpdateMagazineAsync(_editingMagazineId.Value, dto);
|
|
}
|
|
|
|
IsEditing = false;
|
|
ClearForm();
|
|
await LoadMagazinesAsync();
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error saving magazine");
|
|
ErrorMessage = _localizer["FailedToSaveMagazine"];
|
|
HasError = true;
|
|
}
|
|
}
|
|
|
|
// --- Cancel edit ---
|
|
private void CancelEdit()
|
|
{
|
|
IsEditing = false;
|
|
IsEditingExisting = false;
|
|
_editingMagazineId = null;
|
|
ClearForm();
|
|
HasError = false;
|
|
ErrorMessage = string.Empty;
|
|
}
|
|
|
|
// ======================== SYNOPSIS ========================
|
|
|
|
private void InitializeLanguages()
|
|
{
|
|
AvailableLanguages =
|
|
[
|
|
new LanguageItem { Code = "eng", DisplayName = "English" },
|
|
new LanguageItem { Code = "spa", DisplayName = "Español" },
|
|
new LanguageItem { Code = "deu", DisplayName = "Deutsch" },
|
|
new LanguageItem { Code = "fra", DisplayName = "Français" },
|
|
new LanguageItem { Code = "lat", DisplayName = "Latina" },
|
|
new LanguageItem { Code = "por", DisplayName = "Português (Brasil)" }
|
|
];
|
|
|
|
SelectedLanguage = AvailableLanguages[0];
|
|
}
|
|
|
|
private async Task OpenSynopsisAsync(MagazineDto? magazine)
|
|
{
|
|
if(magazine?.Id == null) return;
|
|
|
|
try
|
|
{
|
|
SynopsisMagazineId = magazine.Id;
|
|
SynopsisText = string.Empty;
|
|
IsEditing = false;
|
|
ExistingSynopses.Clear();
|
|
|
|
List<DocumentSynopsisDto> synopses = await _magazinesService.GetSynopsesAsync(magazine.Id.Value);
|
|
|
|
foreach(DocumentSynopsisDto s in synopses)
|
|
ExistingSynopses.Add(s);
|
|
|
|
SelectedLanguage = AvailableLanguages.FirstOrDefault(l =>
|
|
ExistingSynopses.All(s => s.LanguageCode != l.Code)) ??
|
|
AvailableLanguages[0];
|
|
|
|
DocumentSynopsisDto? existing =
|
|
ExistingSynopses.FirstOrDefault(s => s.LanguageCode == SelectedLanguage.Code);
|
|
|
|
if(existing != null)
|
|
SynopsisText = existing.Text ?? string.Empty;
|
|
|
|
IsEditingSynopsis = true;
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error loading synopses for magazine {Id}", magazine.Id);
|
|
SynopsisText = string.Empty;
|
|
IsEditingSynopsis = true;
|
|
}
|
|
}
|
|
|
|
partial void OnSelectedLanguageChanged(LanguageItem? value)
|
|
{
|
|
if(value == null || ExistingSynopses.Count == 0)
|
|
{
|
|
SynopsisText = string.Empty;
|
|
return;
|
|
}
|
|
|
|
DocumentSynopsisDto? existing = ExistingSynopses.FirstOrDefault(s => s.LanguageCode == value.Code);
|
|
SynopsisText = existing?.Text ?? string.Empty;
|
|
}
|
|
|
|
private async Task SaveSynopsisAsync()
|
|
{
|
|
if(SynopsisMagazineId == null || SelectedLanguage == null) return;
|
|
|
|
try
|
|
{
|
|
var dto = new DocumentSynopsisDto
|
|
{
|
|
Text = SynopsisText,
|
|
LanguageCode = SelectedLanguage.Code
|
|
};
|
|
|
|
await _magazinesService.UpsertSynopsisAsync(SynopsisMagazineId.Value, dto);
|
|
|
|
ExistingSynopses.Clear();
|
|
|
|
List<DocumentSynopsisDto> synopses =
|
|
await _magazinesService.GetSynopsesAsync(SynopsisMagazineId.Value);
|
|
|
|
foreach(DocumentSynopsisDto s in synopses) ExistingSynopses.Add(s);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error saving synopsis");
|
|
ErrorMessage = _localizer["FailedToSaveMagazine"];
|
|
HasError = true;
|
|
}
|
|
}
|
|
|
|
private void EditSynopsis(DocumentSynopsisDto? synopsis)
|
|
{
|
|
if(synopsis?.LanguageCode == null) return;
|
|
SelectedLanguage = AvailableLanguages.FirstOrDefault(l => l.Code == synopsis.LanguageCode);
|
|
SynopsisText = synopsis.Text ?? string.Empty;
|
|
}
|
|
|
|
private async Task DeleteSynopsisAsync(DocumentSynopsisDto? synopsis)
|
|
{
|
|
if(SynopsisMagazineId == null || synopsis?.LanguageCode == null) return;
|
|
|
|
try
|
|
{
|
|
await _magazinesService.DeleteSynopsisAsync(SynopsisMagazineId.Value, synopsis.LanguageCode);
|
|
ExistingSynopses.Remove(synopsis);
|
|
SynopsisText = string.Empty;
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error deleting synopsis");
|
|
ErrorMessage = _localizer["FailedToDeleteTranslation"];
|
|
HasError = true;
|
|
}
|
|
}
|
|
|
|
private void CancelSynopsis()
|
|
{
|
|
IsEditingSynopsis = false;
|
|
SynopsisMagazineId = null;
|
|
SynopsisText = string.Empty;
|
|
ExistingSynopses.Clear();
|
|
}
|
|
|
|
// ======================== JUNCTION MANAGEMENT ========================
|
|
|
|
private async Task LoadAllJunctionsAsync(long magazineId)
|
|
{
|
|
await Task.WhenAll(
|
|
LoadMagazinePeopleAsync(magazineId),
|
|
LoadMagazineCompaniesAsync(magazineId),
|
|
LoadMagazineMachinesAsync(magazineId),
|
|
LoadMagazineMachineFamiliesAsync(magazineId)
|
|
);
|
|
}
|
|
|
|
// --- People ---
|
|
private async Task LoadMagazinePeopleAsync(long magazineId)
|
|
{
|
|
MagazinePeople.Clear(); MagazinePeopleDisplays.Clear();
|
|
|
|
try
|
|
{
|
|
List<PersonByMagazineDto> items = await _magazinesService.GetPeopleByMagazineAsync(magazineId);
|
|
|
|
foreach(PersonByMagazineDto p in items)
|
|
{
|
|
MagazinePeople.Add(p);
|
|
string name = p.DisplayName ?? p.Alias ?? $"{p.Name} {p.Surname}".Trim();
|
|
MagazinePeopleDisplays.Add($"{name} ({p.Role})");
|
|
}
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading people for magazine"); }
|
|
}
|
|
|
|
private async Task AddPersonAsync()
|
|
{
|
|
if(_editingMagazineId == null || SelectedAvailablePerson?.Id == null || SelectedPersonRole?.Id == null)
|
|
return;
|
|
|
|
try
|
|
{
|
|
await _magazinesService.AddPersonToMagazineAsync(new PersonByMagazineDto
|
|
{
|
|
PersonId = SelectedAvailablePerson.Id,
|
|
MagazineId = _editingMagazineId,
|
|
RoleId = SelectedPersonRole.Id
|
|
});
|
|
|
|
SelectedAvailablePerson = null;
|
|
await LoadMagazinePeopleAsync(_editingMagazineId.Value);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error adding person to magazine");
|
|
ErrorMessage = _localizer["FailedToSaveMagazine"];
|
|
HasError = true;
|
|
}
|
|
}
|
|
|
|
private async Task RemovePersonByDisplayAsync(string? display)
|
|
{
|
|
if(display == null || _editingMagazineId == null) return;
|
|
|
|
int idx = MagazinePeopleDisplays.IndexOf(display);
|
|
|
|
if(idx >= 0 && idx < MagazinePeople.Count && MagazinePeople[idx].Id.HasValue)
|
|
{
|
|
try
|
|
{
|
|
await _magazinesService.RemovePersonFromMagazineAsync(MagazinePeople[idx].Id!.Value);
|
|
await LoadMagazinePeopleAsync(_editingMagazineId.Value);
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error removing person from magazine"); }
|
|
}
|
|
}
|
|
|
|
// --- Companies ---
|
|
private async Task LoadMagazineCompaniesAsync(long magazineId)
|
|
{
|
|
MagazineCompanies.Clear(); MagazineCompanyDisplays.Clear();
|
|
|
|
try
|
|
{
|
|
List<CompanyByMagazineDto> items = await _magazinesService.GetCompaniesByMagazineAsync(magazineId);
|
|
|
|
foreach(CompanyByMagazineDto c in items)
|
|
{
|
|
MagazineCompanies.Add(c);
|
|
MagazineCompanyDisplays.Add($"{c.Company} ({c.Role})");
|
|
}
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading companies for magazine"); }
|
|
}
|
|
|
|
private async Task AddCompanyAsync()
|
|
{
|
|
if(_editingMagazineId == null || SelectedAvailableCompany?.Id == null || SelectedCompanyRole?.Id == null)
|
|
return;
|
|
|
|
try
|
|
{
|
|
await _magazinesService.AddCompanyToMagazineAsync(new CompanyByMagazineDto
|
|
{
|
|
CompanyId = SelectedAvailableCompany.Id,
|
|
MagazineId = _editingMagazineId,
|
|
RoleId = SelectedCompanyRole.Id
|
|
});
|
|
|
|
SelectedAvailableCompany = null;
|
|
await LoadMagazineCompaniesAsync(_editingMagazineId.Value);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error adding company to magazine");
|
|
ErrorMessage = _localizer["FailedToSaveMagazine"];
|
|
HasError = true;
|
|
}
|
|
}
|
|
|
|
private async Task RemoveCompanyByDisplayAsync(string? display)
|
|
{
|
|
if(display == null || _editingMagazineId == null) return;
|
|
|
|
int idx = MagazineCompanyDisplays.IndexOf(display);
|
|
|
|
if(idx >= 0 && idx < MagazineCompanies.Count && MagazineCompanies[idx].Id.HasValue)
|
|
{
|
|
try
|
|
{
|
|
await _magazinesService.RemoveCompanyFromMagazineAsync(MagazineCompanies[idx].Id!.Value);
|
|
await LoadMagazineCompaniesAsync(_editingMagazineId.Value);
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error removing company from magazine"); }
|
|
}
|
|
}
|
|
|
|
// --- Machines ---
|
|
private async Task LoadMagazineMachinesAsync(long magazineId)
|
|
{
|
|
MagazineMachines.Clear(); MagazineMachineDisplays.Clear();
|
|
|
|
try
|
|
{
|
|
List<MagazineByMachineDto> items = await _magazinesService.GetMachinesByMagazineAsync(magazineId);
|
|
|
|
foreach(MagazineByMachineDto m in items)
|
|
{
|
|
MagazineMachines.Add(m);
|
|
MagazineMachineDisplays.Add(m.Machine ?? $"Machine #{m.MachineId}");
|
|
}
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading machines for magazine"); }
|
|
|
|
RefreshAvailableMachines();
|
|
}
|
|
|
|
private async Task AddMachineAsync()
|
|
{
|
|
if(_editingMagazineId == null || SelectedAvailableMachine?.Id == null) return;
|
|
|
|
try
|
|
{
|
|
await _magazinesService.AddMachineToMagazineAsync(new MagazineByMachineDto
|
|
{
|
|
MagazineId = _editingMagazineId,
|
|
MachineId = SelectedAvailableMachine.Id
|
|
});
|
|
|
|
SelectedAvailableMachine = null;
|
|
await LoadMagazineMachinesAsync(_editingMagazineId.Value);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error adding machine to magazine");
|
|
ErrorMessage = _localizer["FailedToSaveMagazine"];
|
|
HasError = true;
|
|
}
|
|
}
|
|
|
|
private async Task RemoveMachineByDisplayAsync(string? display)
|
|
{
|
|
if(display == null || _editingMagazineId == null) return;
|
|
|
|
int idx = MagazineMachineDisplays.IndexOf(display);
|
|
|
|
if(idx >= 0 && idx < MagazineMachines.Count && MagazineMachines[idx].Id.HasValue)
|
|
{
|
|
try
|
|
{
|
|
await _magazinesService.RemoveMachineFromMagazineAsync(MagazineMachines[idx].Id!.Value);
|
|
await LoadMagazineMachinesAsync(_editingMagazineId.Value);
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error removing machine from magazine"); }
|
|
}
|
|
}
|
|
|
|
// --- Machine Families ---
|
|
private async Task LoadMagazineMachineFamiliesAsync(long magazineId)
|
|
{
|
|
MagazineMachineFamilies.Clear(); MagazineMachineFamilyDisplays.Clear();
|
|
|
|
try
|
|
{
|
|
List<MagazineByMachineFamilyDto> items =
|
|
await _magazinesService.GetMachineFamiliesByMagazineAsync(magazineId);
|
|
|
|
foreach(MagazineByMachineFamilyDto f in items)
|
|
{
|
|
MagazineMachineFamilies.Add(f);
|
|
MagazineMachineFamilyDisplays.Add(f.MachineFamily ?? $"Family #{f.MachineFamilyId}");
|
|
}
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading machine families for magazine"); }
|
|
|
|
RefreshAvailableMachineFamilies();
|
|
}
|
|
|
|
private async Task AddMachineFamilyAsync()
|
|
{
|
|
if(_editingMagazineId == null || SelectedAvailableMachineFamily?.Id == null) return;
|
|
|
|
try
|
|
{
|
|
await _magazinesService.AddMachineFamilyToMagazineAsync(new MagazineByMachineFamilyDto
|
|
{
|
|
MagazineId = _editingMagazineId,
|
|
MachineFamilyId = SelectedAvailableMachineFamily.Id
|
|
});
|
|
|
|
SelectedAvailableMachineFamily = null;
|
|
await LoadMagazineMachineFamiliesAsync(_editingMagazineId.Value);
|
|
}
|
|
catch(Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error adding machine family to magazine");
|
|
ErrorMessage = _localizer["FailedToSaveMagazine"];
|
|
HasError = true;
|
|
}
|
|
}
|
|
|
|
private async Task RemoveMachineFamilyByDisplayAsync(string? display)
|
|
{
|
|
if(display == null || _editingMagazineId == null) return;
|
|
|
|
int idx = MagazineMachineFamilyDisplays.IndexOf(display);
|
|
|
|
if(idx >= 0 && idx < MagazineMachineFamilies.Count && MagazineMachineFamilies[idx].Id.HasValue)
|
|
{
|
|
try
|
|
{
|
|
await _magazinesService.RemoveMachineFamilyFromMagazineAsync(
|
|
MagazineMachineFamilies[idx].Id!.Value);
|
|
|
|
await LoadMagazineMachineFamiliesAsync(_editingMagazineId.Value);
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error removing machine family from magazine"); }
|
|
}
|
|
}
|
|
|
|
// ======================== HELPERS ========================
|
|
|
|
private void RefreshAvailableMachines()
|
|
{
|
|
AvailableMachines.Clear();
|
|
|
|
if(_allMachinesList == null) return;
|
|
|
|
HashSet<int> assigned =
|
|
new(MagazineMachines.Where(m => m.MachineId.HasValue).Select(m => m.MachineId!.Value));
|
|
|
|
foreach(MachineDto m in _allMachinesList)
|
|
if(m.Id.HasValue && !assigned.Contains(m.Id.Value))
|
|
AvailableMachines.Add(m);
|
|
}
|
|
|
|
private void RefreshAvailableMachineFamilies()
|
|
{
|
|
AvailableMachineFamilies.Clear();
|
|
|
|
if(_allMachineFamiliesList == null) return;
|
|
|
|
HashSet<int> assigned =
|
|
new(MagazineMachineFamilies.Where(f => f.MachineFamilyId.HasValue)
|
|
.Select(f => f.MachineFamilyId!.Value));
|
|
|
|
foreach(MachineFamilyDto f in _allMachineFamiliesList)
|
|
if(f.Id.HasValue && !assigned.Contains(f.Id.Value))
|
|
AvailableMachineFamilies.Add(f);
|
|
}
|
|
|
|
// --- Filtering ---
|
|
public void ApplyFilter()
|
|
{
|
|
FilteredMagazines.Clear();
|
|
IEnumerable<MagazineDto> source = (IEnumerable<MagazineDto>?)_allMagazines ?? Magazines;
|
|
|
|
if(!string.IsNullOrWhiteSpace(FilterText))
|
|
source = source.Where(m =>
|
|
(m.Title != null && m.Title.Contains(FilterText, StringComparison.OrdinalIgnoreCase)) ||
|
|
(m.NativeTitle != null && m.NativeTitle.Contains(FilterText, StringComparison.OrdinalIgnoreCase)) ||
|
|
(m.SortTitle != null && m.SortTitle.Contains(FilterText, StringComparison.OrdinalIgnoreCase)) ||
|
|
(m.Issn != null && m.Issn.Contains(FilterText, StringComparison.OrdinalIgnoreCase)));
|
|
|
|
foreach(MagazineDto m in source) FilteredMagazines.Add(m);
|
|
}
|
|
|
|
// --- Load picker data ---
|
|
public async Task LoadPickerDataAsync()
|
|
{
|
|
try
|
|
{
|
|
List<Iso31661NumericDto>? countriesResponse = await _apiClient.Iso31661Numeric.GetAsync();
|
|
Countries.Clear();
|
|
if(countriesResponse != null)
|
|
foreach(Iso31661NumericDto c in countriesResponse) Countries.Add(c);
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading countries"); }
|
|
|
|
try
|
|
{
|
|
_allRolesList = await _magazinesService.GetDocumentRolesAsync();
|
|
AvailableRoles.Clear();
|
|
foreach(DocumentRoleDto r in _allRolesList) AvailableRoles.Add(r);
|
|
}
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading document roles"); }
|
|
|
|
try { _allPeopleList = await _apiClient.People.GetAsync(); }
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading people"); }
|
|
|
|
try { _allCompaniesList = await _apiClient.Companies.GetAsync(); }
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading companies"); }
|
|
|
|
try { _allMachinesList = await _apiClient.Machines.GetAsync(); }
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading machines"); }
|
|
|
|
try { _allMachineFamiliesList = await _apiClient.MachineFamilies.GetAsync(); }
|
|
catch(Exception ex) { _logger.LogError(ex, "Error loading machine families"); }
|
|
}
|
|
|
|
// --- People search ---
|
|
public void UpdatePeopleSuggestions(string query)
|
|
{
|
|
AvailablePeople.Clear();
|
|
if(_allPeopleList == null) return;
|
|
|
|
IEnumerable<PersonDto> source = _allPeopleList;
|
|
if(!string.IsNullOrWhiteSpace(query))
|
|
source = source.Where(p =>
|
|
(p.Name != null && p.Name.Contains(query, StringComparison.OrdinalIgnoreCase)) ||
|
|
(p.Surname != null && p.Surname.Contains(query, StringComparison.OrdinalIgnoreCase)) ||
|
|
(p.DisplayName != null && p.DisplayName.Contains(query, StringComparison.OrdinalIgnoreCase)));
|
|
|
|
foreach(PersonDto p in source) AvailablePeople.Add(p);
|
|
}
|
|
|
|
// --- Company search ---
|
|
public void UpdateCompanySuggestions(string query)
|
|
{
|
|
AvailableCompanies.Clear();
|
|
if(_allCompaniesList == null) return;
|
|
|
|
IEnumerable<CompanyDto> source = _allCompaniesList;
|
|
if(!string.IsNullOrWhiteSpace(query))
|
|
source = source.Where(c =>
|
|
c.Name != null && c.Name.Contains(query, StringComparison.OrdinalIgnoreCase));
|
|
|
|
foreach(CompanyDto c in source) AvailableCompanies.Add(c);
|
|
}
|
|
|
|
// --- Form helpers ---
|
|
private void ClearForm()
|
|
{
|
|
MagazineTitle = string.Empty;
|
|
NativeTitle = string.Empty;
|
|
SortTitle = string.Empty;
|
|
Issn = string.Empty;
|
|
Published = null;
|
|
PublishedPrecision = 0;
|
|
FirstPublication = null;
|
|
FirstPublicationPrecision = 0;
|
|
SelectedCountry = null;
|
|
|
|
MagazinePeople.Clear(); MagazinePeopleDisplays.Clear();
|
|
MagazineCompanies.Clear(); MagazineCompanyDisplays.Clear();
|
|
MagazineMachines.Clear(); MagazineMachineDisplays.Clear();
|
|
MagazineMachineFamilies.Clear(); MagazineMachineFamilyDisplays.Clear();
|
|
AvailableMachines.Clear(); AvailableMachineFamilies.Clear();
|
|
SelectedAvailablePerson = null;
|
|
SelectedAvailableCompany = null;
|
|
SelectedAvailableMachine = null;
|
|
SelectedAvailableMachineFamily = null;
|
|
SelectedPersonRole = null;
|
|
SelectedCompanyRole = null;
|
|
|
|
HasError = false;
|
|
ErrorMessage = string.Empty;
|
|
}
|
|
|
|
private void PopulateForm(MagazineDto magazine)
|
|
{
|
|
MagazineTitle = magazine.Title ?? string.Empty;
|
|
NativeTitle = magazine.NativeTitle ?? string.Empty;
|
|
SortTitle = magazine.SortTitle ?? string.Empty;
|
|
Issn = magazine.Issn ?? string.Empty;
|
|
Published = magazine.Published;
|
|
PublishedPrecision = magazine.PublishedPrecision ?? 0;
|
|
FirstPublication = magazine.FirstPublication;
|
|
FirstPublicationPrecision = magazine.FirstPublicationPrecision ?? 0;
|
|
|
|
SelectedCountry = magazine.CountryId.HasValue
|
|
? Countries.FirstOrDefault(c => c.Id == magazine.CountryId.Value)
|
|
: null;
|
|
}
|
|
}
|