mirror of
https://github.com/claunia/marechai.git
synced 2025-12-16 19:14:25 +00:00
Add company detail page.
This commit is contained in:
@@ -1,19 +1,23 @@
|
||||
<Application x:Class="Marechai.App.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Marechai.App.Presentation.Converters">
|
||||
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- Load WinUI resources -->
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Load Uno.UI.Toolkit resources -->
|
||||
<ToolkitResources xmlns="using:Uno.Toolkit.UI" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- Load WinUI resources -->
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Load Uno.UI.Toolkit resources -->
|
||||
<ToolkitResources xmlns="using:Uno.Toolkit.UI" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<!-- Add resources here -->
|
||||
<!-- Add resources here -->
|
||||
<local:ObjectToVisibilityConverter x:Key="ObjectToVisibilityConverter" />
|
||||
<local:StringToVisibilityConverter x:Key="StringToVisibilityConverter" />
|
||||
<local:ZeroToVisibilityConverter x:Key="ZeroToVisibilityConverter" />
|
||||
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
|
||||
</Application>
|
||||
@@ -10,6 +10,7 @@ using Uno.Extensions.Http;
|
||||
using Uno.Extensions.Localization;
|
||||
using Uno.Extensions.Navigation;
|
||||
using Uno.UI;
|
||||
using CompanyDetailViewModel = Marechai.App.Presentation.ViewModels.CompanyDetailViewModel;
|
||||
using ComputersListViewModel = Marechai.App.Presentation.ViewModels.ComputersListViewModel;
|
||||
using ComputersViewModel = Marechai.App.Presentation.ViewModels.ComputersViewModel;
|
||||
using MachineViewViewModel = Marechai.App.Presentation.ViewModels.MachineViewViewModel;
|
||||
@@ -113,6 +114,8 @@ public partial class App : Application
|
||||
services.AddSingleton<ConsolesViewModel>();
|
||||
services.AddSingleton<CompaniesService>();
|
||||
services.AddSingleton<CompaniesViewModel>();
|
||||
services.AddSingleton<CompanyDetailService>();
|
||||
services.AddSingleton<CompanyDetailViewModel>();
|
||||
services.AddSingleton<MachineViewViewModel>();
|
||||
|
||||
services
|
||||
@@ -148,6 +151,7 @@ public partial class App : Application
|
||||
new ViewMap<ConsolesPage, ConsolesViewModel>(),
|
||||
new ViewMap<ConsolesListPage, ConsolesListViewModel>(),
|
||||
new ViewMap<CompaniesPage, CompaniesViewModel>(),
|
||||
new ViewMap<CompanyDetailPage, CompanyDetailViewModel>(),
|
||||
new ViewMap<MachineViewPage, MachineViewViewModel>(),
|
||||
new DataViewMap<SecondPage, SecondViewModel, Entity>());
|
||||
|
||||
@@ -183,7 +187,13 @@ public partial class App : Application
|
||||
ConsolesListViewModel>())
|
||||
]),
|
||||
new RouteMap("companies",
|
||||
views.FindByViewModel<CompaniesViewModel>()),
|
||||
views.FindByViewModel<CompaniesViewModel>(),
|
||||
Nested:
|
||||
[
|
||||
new RouteMap("detail",
|
||||
views.FindByViewModel<
|
||||
CompanyDetailViewModel>())
|
||||
]),
|
||||
new RouteMap("Second",
|
||||
views.FindByViewModel<SecondViewModel>())
|
||||
])
|
||||
|
||||
51
Marechai.App/Presentation/Converters/CompanyConverters.cs
Normal file
51
Marechai.App/Presentation/Converters/CompanyConverters.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
|
||||
namespace Marechai.App.Presentation.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Converts null object to Collapsed visibility
|
||||
/// </summary>
|
||||
public class ObjectToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language) =>
|
||||
value != null ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts empty/null string to Collapsed visibility
|
||||
/// </summary>
|
||||
public class StringToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if(value is string str && !string.IsNullOrWhiteSpace(str)) return Visibility.Visible;
|
||||
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts zero count to Collapsed visibility, otherwise Visible
|
||||
/// </summary>
|
||||
public class ZeroToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if(value is int count && count > 0) return Visibility.Visible;
|
||||
|
||||
if(value is long longCount && longCount > 0) return Visibility.Visible;
|
||||
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language) =>
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/******************************************************************************
|
||||
// MARECHAI: Master repository of computing history artifacts information
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2003-2026 Natalia Portillo
|
||||
*******************************************************************************/
|
||||
|
||||
namespace Marechai.App.Presentation.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Navigation parameter for the CompanyDetailPage containing both the company ID and the navigation source.
|
||||
/// </summary>
|
||||
public class CompanyDetailNavigationParameter
|
||||
{
|
||||
public required int CompanyId { get; init; }
|
||||
public object? NavigationSource { get; init; }
|
||||
}
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Marechai.App.Helpers;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Services;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
@@ -14,13 +15,12 @@ namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public partial class CompaniesViewModel : ObservableObject
|
||||
{
|
||||
private readonly List<CompanyListItem> _allCompanies = [];
|
||||
private readonly CompaniesService _companiesService;
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<CompaniesViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
private readonly List<CompanyListItem> _allCompanies = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyListItem> _companiesList = [];
|
||||
|
||||
@@ -146,8 +146,14 @@ public partial class CompaniesViewModel : ObservableObject
|
||||
|
||||
_logger.LogInformation("Navigating to company: {CompanyName} (ID: {CompanyId})", company.Name, company.Id);
|
||||
|
||||
// TODO: Implement company detail view
|
||||
// For now, just log the navigation
|
||||
// Navigate to company detail view with navigation parameter
|
||||
var navParam = new CompanyDetailNavigationParameter
|
||||
{
|
||||
CompanyId = company.Id,
|
||||
NavigationSource = this
|
||||
};
|
||||
|
||||
await _navigator.NavigateViewModelAsync<CompanyDetailViewModel>(this, data: navParam);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
373
Marechai.App/Presentation/ViewModels/CompanyDetailViewModel.cs
Normal file
373
Marechai.App/Presentation/ViewModels/CompanyDetailViewModel.cs
Normal file
@@ -0,0 +1,373 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Marechai.App.Helpers;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Services;
|
||||
using Marechai.Data;
|
||||
using Uno.Extensions.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.ViewModels;
|
||||
|
||||
public partial class CompanyDetailViewModel : ObservableObject
|
||||
{
|
||||
private readonly CompanyDetailService _companyDetailService;
|
||||
private readonly IStringLocalizer _localizer;
|
||||
private readonly ILogger<CompanyDetailViewModel> _logger;
|
||||
private readonly INavigator _navigator;
|
||||
|
||||
[ObservableProperty]
|
||||
private CompanyDto? _company;
|
||||
|
||||
[ObservableProperty]
|
||||
private int _companyId;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyDetailMachine> _computers = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private string _computersFilterText = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private string _consoelsFilterText = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyDetailMachine> _consoles = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private string _errorMessage = string.Empty;
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyDetailMachine> _filteredComputers = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<CompanyDetailMachine> _filteredConsoles = [];
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _hasError;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isDataLoaded;
|
||||
|
||||
[ObservableProperty]
|
||||
private bool _isLoading;
|
||||
|
||||
[ObservableProperty]
|
||||
private CompanyDto? _soldToCompany;
|
||||
|
||||
public CompanyDetailViewModel(CompanyDetailService companyDetailService, IStringLocalizer localizer,
|
||||
ILogger<CompanyDetailViewModel> logger, INavigator navigator)
|
||||
{
|
||||
_companyDetailService = companyDetailService;
|
||||
_localizer = localizer;
|
||||
_logger = logger;
|
||||
_navigator = navigator;
|
||||
LoadData = new AsyncRelayCommand(LoadDataAsync);
|
||||
GoBackCommand = new AsyncRelayCommand(GoBackAsync);
|
||||
NavigateToMachineCommand = new AsyncRelayCommand<CompanyDetailMachine>(NavigateToMachineAsync);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display text for the company's status
|
||||
/// </summary>
|
||||
public string CompanyStatusDisplay => Company != null ? GetStatusMessage(Company) : string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the display text for the company's founded date
|
||||
/// </summary>
|
||||
public string CompanyFoundedDateDisplay => Company != null ? GetFoundedDateDisplay(Company) : string.Empty;
|
||||
|
||||
public IAsyncRelayCommand LoadData { get; }
|
||||
public ICommand GoBackCommand { get; }
|
||||
public IAsyncRelayCommand<CompanyDetailMachine> NavigateToMachineCommand { get; }
|
||||
public string Title { get; } = "Company Details";
|
||||
|
||||
partial void OnCompanyChanged(CompanyDto? oldValue, CompanyDto? newValue)
|
||||
{
|
||||
// Notify that computed properties have changed
|
||||
OnPropertyChanged(nameof(CompanyStatusDisplay));
|
||||
OnPropertyChanged(nameof(CompanyFoundedDateDisplay));
|
||||
}
|
||||
|
||||
partial void OnComputersFilterTextChanged(string value)
|
||||
{
|
||||
FilterComputers(value);
|
||||
}
|
||||
|
||||
partial void OnConsoelsFilterTextChanged(string value)
|
||||
{
|
||||
FilterConsoles(value);
|
||||
}
|
||||
|
||||
private void FilterComputers(string filterText)
|
||||
{
|
||||
ObservableCollection<CompanyDetailMachine> filtered = string.IsNullOrWhiteSpace(filterText)
|
||||
? new ObservableCollection<
|
||||
CompanyDetailMachine>(Computers)
|
||||
: new
|
||||
ObservableCollection<
|
||||
CompanyDetailMachine>(Computers.Where(c =>
|
||||
c.Name.Contains(filterText,
|
||||
StringComparison
|
||||
.OrdinalIgnoreCase)));
|
||||
|
||||
FilteredComputers = filtered;
|
||||
}
|
||||
|
||||
private void FilterConsoles(string filterText)
|
||||
{
|
||||
ObservableCollection<CompanyDetailMachine> filtered = string.IsNullOrWhiteSpace(filterText)
|
||||
? new ObservableCollection<
|
||||
CompanyDetailMachine>(Consoles)
|
||||
: new
|
||||
ObservableCollection<
|
||||
CompanyDetailMachine>(Consoles.Where(c =>
|
||||
c.Name.Contains(filterText,
|
||||
StringComparison
|
||||
.OrdinalIgnoreCase)));
|
||||
|
||||
FilteredConsoles = filtered;
|
||||
}
|
||||
|
||||
private async Task NavigateToMachineAsync(CompanyDetailMachine? machine)
|
||||
{
|
||||
if(machine == null) return;
|
||||
|
||||
var navParam = new MachineViewNavigationParameter
|
||||
{
|
||||
MachineId = machine.Id,
|
||||
NavigationSource = this
|
||||
};
|
||||
|
||||
await _navigator.NavigateViewModelAsync<MachineViewViewModel>(this, data: navParam);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the formatted founding date with unknown handling
|
||||
/// </summary>
|
||||
public string GetFoundedDateDisplay(CompanyDto company)
|
||||
{
|
||||
if(company.Founded is null) return string.Empty;
|
||||
|
||||
DateTime date = company.Founded.Value.DateTime;
|
||||
|
||||
if(company.FoundedMonthIsUnknown ?? false) return $"{date.Year}.";
|
||||
|
||||
if(company.FoundedDayIsUnknown ?? false) return $"{date:Y}.";
|
||||
|
||||
return $"{date:D}.";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the formatted sold/event date with unknown handling
|
||||
/// </summary>
|
||||
public string GetEventDateDisplay(CompanyDto? company, bool monthUnknown = false, bool dayUnknown = false)
|
||||
{
|
||||
if(company?.Sold is null) return _localizer["unknown date"].Value;
|
||||
|
||||
DateTime date = company.Sold.Value.DateTime;
|
||||
|
||||
if(monthUnknown || (company.SoldMonthIsUnknown ?? false)) return $"{date.Year}";
|
||||
|
||||
if(dayUnknown || (company.SoldDayIsUnknown ?? false)) return $"{date:Y}";
|
||||
|
||||
return $"{date:D}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the status message for the company
|
||||
/// </summary>
|
||||
public string GetStatusMessage(CompanyDto company)
|
||||
{
|
||||
return company.Status switch
|
||||
{
|
||||
1 => _localizer["Company is active."].Value,
|
||||
2 => GetSoldStatusMessage(company),
|
||||
3 => GetMergedStatusMessage(company),
|
||||
4 => GetBankruptcyMessage(company),
|
||||
5 => GetDefunctMessage(company),
|
||||
6 => GetRenamedStatusMessage(company),
|
||||
_ => _localizer["Current company status is unknown."].Value
|
||||
};
|
||||
}
|
||||
|
||||
private string GetSoldStatusMessage(CompanyDto company)
|
||||
{
|
||||
if(SoldToCompany != null)
|
||||
{
|
||||
return string.Format(_localizer["Company sold to {0} on {1}."].Value,
|
||||
SoldToCompany.Name,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
if(company.Sold != null)
|
||||
{
|
||||
return string.Format(_localizer["Company sold on {0} to an unknown company."].Value,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
return SoldToCompany != null
|
||||
? string.Format(_localizer["Company sold to {0} on an unknown date."].Value, SoldToCompany.Name)
|
||||
: _localizer["Company was sold to an unknown company on an unknown date."].Value;
|
||||
}
|
||||
|
||||
private string GetMergedStatusMessage(CompanyDto company)
|
||||
{
|
||||
if(SoldToCompany != null)
|
||||
{
|
||||
return string.Format(_localizer["Company merged on {0} to form {1}."].Value,
|
||||
GetEventDateDisplay(company),
|
||||
SoldToCompany.Name);
|
||||
}
|
||||
|
||||
if(company.Sold != null)
|
||||
{
|
||||
return string.Format(_localizer["Company merged on {0} to form an unknown company."].Value,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
return SoldToCompany != null
|
||||
? string.Format(_localizer["Company merged on an unknown date to form {0}."].Value,
|
||||
SoldToCompany.Name)
|
||||
: _localizer["Company merged to form an unknown company on an unknown date."].Value;
|
||||
}
|
||||
|
||||
private string GetBankruptcyMessage(CompanyDto company) => company.Sold != null
|
||||
? string.Format(_localizer
|
||||
["Company declared bankruptcy on {0}."]
|
||||
.Value,
|
||||
GetEventDateDisplay(company))
|
||||
: _localizer
|
||||
["Company declared bankruptcy on an unknown date."]
|
||||
.Value;
|
||||
|
||||
private string GetDefunctMessage(CompanyDto company) => company.Sold != null
|
||||
? string.Format(_localizer
|
||||
["Company ceased operations on {0}."]
|
||||
.Value,
|
||||
GetEventDateDisplay(company))
|
||||
: _localizer
|
||||
["Company ceased operations on an unknown date."]
|
||||
.Value;
|
||||
|
||||
private string GetRenamedStatusMessage(CompanyDto company)
|
||||
{
|
||||
if(SoldToCompany != null)
|
||||
{
|
||||
return string.Format(_localizer["Company renamed to {0} on {1}."].Value,
|
||||
SoldToCompany.Name,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
if(company.Sold != null)
|
||||
{
|
||||
return string.Format(_localizer["Company was renamed on {0} to an unknown name."].Value,
|
||||
GetEventDateDisplay(company));
|
||||
}
|
||||
|
||||
return SoldToCompany != null
|
||||
? string.Format(_localizer["Company renamed to {0} on an unknown date."].Value, SoldToCompany.Name)
|
||||
: _localizer["Company renamed to an unknown name on an unknown date."].Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads company details from the API
|
||||
/// </summary>
|
||||
private async Task LoadDataAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsLoading = true;
|
||||
ErrorMessage = string.Empty;
|
||||
HasError = false;
|
||||
IsDataLoaded = false;
|
||||
|
||||
if(CompanyId <= 0)
|
||||
{
|
||||
ErrorMessage = _localizer["Invalid company ID."].Value;
|
||||
HasError = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Load company details
|
||||
Company = await _companyDetailService.GetCompanyByIdAsync(CompanyId);
|
||||
|
||||
if(Company is null)
|
||||
{
|
||||
ErrorMessage = _localizer["Company not found."].Value;
|
||||
HasError = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Load sold-to company if applicable
|
||||
if(Company.SoldToId != null)
|
||||
{
|
||||
int soldToId = UntypedNodeExtractor.ExtractInt(Company.SoldToId);
|
||||
if(soldToId > 0) SoldToCompany = await _companyDetailService.GetSoldToCompanyAsync(soldToId);
|
||||
}
|
||||
|
||||
// Load computers and consoles made by this company
|
||||
List<MachineDto> machines = await _companyDetailService.GetComputersByCompanyAsync(CompanyId);
|
||||
Computers.Clear();
|
||||
Consoles.Clear();
|
||||
FilteredComputers.Clear();
|
||||
FilteredConsoles.Clear();
|
||||
|
||||
foreach(MachineDto machine in machines)
|
||||
{
|
||||
int machineId = UntypedNodeExtractor.ExtractInt(machine.Id);
|
||||
|
||||
var machineItem = new CompanyDetailMachine
|
||||
{
|
||||
Id = machineId,
|
||||
Name = machine.Name ?? string.Empty
|
||||
};
|
||||
|
||||
// Categorize by machine type enum
|
||||
if(machine.Type == (int)MachineType.Computer)
|
||||
Computers.Add(machineItem);
|
||||
else if(machine.Type == (int)MachineType.Console) Consoles.Add(machineItem);
|
||||
}
|
||||
|
||||
// Initialize filtered lists
|
||||
FilteredComputers = new ObservableCollection<CompanyDetailMachine>(Computers);
|
||||
FilteredConsoles = new ObservableCollection<CompanyDetailMachine>(Consoles);
|
||||
|
||||
IsDataLoaded = true;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError("Error loading company details: {Exception}", ex.Message);
|
||||
ErrorMessage = _localizer["Failed to load company details. Please try again later."].Value;
|
||||
HasError = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles back navigation
|
||||
/// </summary>
|
||||
private async Task GoBackAsync()
|
||||
{
|
||||
await _navigator.NavigateViewModelAsync<CompaniesViewModel>(this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Data model for a machine in the company detail view
|
||||
/// </summary>
|
||||
public class CompanyDetailMachine
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -31,6 +31,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Threading.Tasks;
|
||||
using Humanizer;
|
||||
using Marechai.App.Helpers;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Services;
|
||||
using Marechai.Data;
|
||||
using Microsoft.UI.Xaml;
|
||||
@@ -127,6 +128,19 @@ public partial class MachineViewViewModel : ObservableObject
|
||||
return;
|
||||
}
|
||||
|
||||
// If we came from CompanyDetailViewModel, navigate back to company details
|
||||
if(_navigationSource is CompanyDetailViewModel companyVm)
|
||||
{
|
||||
var navParam = new CompanyDetailNavigationParameter
|
||||
{
|
||||
CompanyId = companyVm.CompanyId
|
||||
};
|
||||
|
||||
await _navigator.NavigateViewModelAsync<CompanyDetailViewModel>(this, data: navParam);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If we came from ConsolesListViewModel, navigate back to consoles list
|
||||
if(_navigationSource is ConsolesListViewModel)
|
||||
{
|
||||
|
||||
@@ -92,7 +92,23 @@
|
||||
<StackPanel Visibility="{Binding IsDataLoaded}"
|
||||
Spacing="8">
|
||||
<ItemsRepeater ItemsSource="{Binding CompaniesList}">
|
||||
<ItemsRepeater.ItemTemplate></ItemsRepeater.ItemTemplate>
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button HorizontalAlignment="Stretch"
|
||||
Command="{Binding DataContext.NavigateToCompanyCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}">
|
||||
<StackPanel Spacing="4"
|
||||
Padding="8">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold" />
|
||||
<TextBlock Text="{Binding FoundationDateDisplay}"
|
||||
FontSize="12"
|
||||
Opacity="0.6" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
59
Marechai.App/Presentation/Views/CompaniesPage.xaml.cs
Normal file
59
Marechai.App/Presentation/Views/CompaniesPage.xaml.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class CompaniesPage : Page
|
||||
{
|
||||
public CompaniesPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += CompaniesPage_DataContextChanged;
|
||||
Loaded += CompaniesPage_Loaded;
|
||||
}
|
||||
|
||||
private void CompaniesPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is not CompaniesViewModel viewModel) return;
|
||||
|
||||
// Trigger data loading
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
|
||||
private void CompaniesPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(args.NewValue is CompaniesViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when data context changes
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
if(DataContext is CompaniesViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when navigating to the page
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSearchTextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
||||
{
|
||||
if(args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
||||
{
|
||||
// The two-way binding will automatically update SearchQuery in ViewModel,
|
||||
// which will trigger OnSearchQueryChanged and filter the list
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSearchQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
|
||||
{
|
||||
// The two-way binding will automatically update SearchQuery in ViewModel,
|
||||
// which will trigger OnSearchQueryChanged and filter the list
|
||||
}
|
||||
}
|
||||
273
Marechai.App/Presentation/Views/CompanyDetailPage.xaml
Normal file
273
Marechai.App/Presentation/Views/CompanyDetailPage.xaml
Normal file
@@ -0,0 +1,273 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Page x:Class="Marechai.App.Presentation.Views.CompanyDetailPage"
|
||||
x:Name="PageRoot"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:utu="using:Uno.Toolkit.UI"
|
||||
NavigationCacheMode="Required"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<Grid utu:SafeArea.Insets="VisibleBounds">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<utu:NavigationBar Grid.Row="0"
|
||||
Content="{Binding Path=Title}">
|
||||
<utu:NavigationBar.MainCommand>
|
||||
<AppBarButton Icon="Back"
|
||||
Label="Back"
|
||||
Command="{Binding GoBackCommand}"
|
||||
AutomationProperties.Name="Go back" />
|
||||
</utu:NavigationBar.MainCommand>
|
||||
</utu:NavigationBar>
|
||||
|
||||
<!-- Content -->
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<StackPanel Padding="16"
|
||||
Spacing="16">
|
||||
|
||||
<!-- Loading State -->
|
||||
<StackPanel Visibility="{Binding IsLoading}"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Padding="32"
|
||||
Spacing="16">
|
||||
<ProgressRing IsActive="True"
|
||||
IsIndeterminate="True"
|
||||
Height="48"
|
||||
Width="48" />
|
||||
<TextBlock Text="Loading..."
|
||||
TextAlignment="Center"
|
||||
FontSize="14" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Error State -->
|
||||
<StackPanel Visibility="{Binding HasError}"
|
||||
Padding="16"
|
||||
Background="{ThemeResource SystemErrorBackgroundColor}"
|
||||
CornerRadius="8"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Error"
|
||||
FontWeight="Bold"
|
||||
Foreground="{ThemeResource SystemErrorTextForegroundColor}" />
|
||||
<TextBlock Text="{Binding ErrorMessage}"
|
||||
Foreground="{ThemeResource SystemErrorTextForegroundColor}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Company Details -->
|
||||
<StackPanel Visibility="{Binding IsDataLoaded}"
|
||||
Spacing="16">
|
||||
|
||||
<!-- Company Name -->
|
||||
<TextBlock Text="{Binding Company.Name}"
|
||||
FontSize="28"
|
||||
FontWeight="Bold"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<!-- Company Status -->
|
||||
<StackPanel Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Status"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding CompanyStatusDisplay}"
|
||||
FontSize="14"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Founded Date -->
|
||||
<StackPanel Visibility="{Binding Company.Founded, Converter={StaticResource ObjectToVisibilityConverter}}"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Founded"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding CompanyFoundedDateDisplay}"
|
||||
FontSize="14" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Legal Name -->
|
||||
<StackPanel Visibility="{Binding Company.LegalName, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Legal Name"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding Company.LegalName}"
|
||||
FontSize="14" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Country -->
|
||||
<StackPanel Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Country"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding Company.Country}"
|
||||
FontSize="14" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Address -->
|
||||
<StackPanel Visibility="{Binding Company.Address, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
Background="{ThemeResource CardBackgroundFillColorDefaultBrush}"
|
||||
CornerRadius="8"
|
||||
Padding="12"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Address"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock TextWrapping="Wrap">
|
||||
<Run Text="{Binding Company.Address}" />
|
||||
<Run Text="{Binding Company.City}" />
|
||||
<Run Text="{Binding Company.PostalCode}" />
|
||||
<Run Text="{Binding Company.Province}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Links Section -->
|
||||
<StackPanel Spacing="8">
|
||||
<TextBlock Text="Links"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
|
||||
<!-- Website -->
|
||||
<HyperlinkButton Visibility="{Binding Company.Website, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
NavigateUri="{Binding Company.Website}">
|
||||
<TextBlock Text="Website" />
|
||||
</HyperlinkButton>
|
||||
|
||||
<!-- Twitter -->
|
||||
<HyperlinkButton Visibility="{Binding Company.Twitter, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
Click="OnTwitterClick">
|
||||
<TextBlock Text="Twitter" />
|
||||
</HyperlinkButton>
|
||||
|
||||
<!-- Facebook -->
|
||||
<HyperlinkButton Visibility="{Binding Company.Facebook, Converter={StaticResource StringToVisibilityConverter}}"
|
||||
Click="OnFacebookClick">
|
||||
<TextBlock Text="Facebook" />
|
||||
</HyperlinkButton>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Computers Section -->
|
||||
<StackPanel Visibility="{Binding Computers.Count, Converter={StaticResource ZeroToVisibilityConverter}}"
|
||||
Spacing="8">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Computers"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding Computers.Count}"
|
||||
FontSize="14"
|
||||
FontWeight="Bold"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Filter Box -->
|
||||
<AutoSuggestBox PlaceholderText="Filter computers..."
|
||||
Text="{Binding ComputersFilterText, Mode=TwoWay}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{ThemeResource ControlElevationBorderBrush}" />
|
||||
|
||||
<!-- Scrollable Computers List -->
|
||||
<ScrollViewer Height="200"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
|
||||
CornerRadius="8">
|
||||
<ItemsRepeater ItemsSource="{Binding FilteredComputers}"
|
||||
Margin="0">
|
||||
<ItemsRepeater.Layout>
|
||||
<StackLayout Spacing="4" />
|
||||
</ItemsRepeater.Layout>
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button Command="{Binding DataContext.NavigateToMachineCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}"
|
||||
Padding="12,8"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="12"
|
||||
TextWrapping="Wrap" />
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Consoles Section -->
|
||||
<StackPanel Visibility="{Binding Consoles.Count, Converter={StaticResource ZeroToVisibilityConverter}}"
|
||||
Spacing="8">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<TextBlock Text="Consoles"
|
||||
FontSize="14"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{ThemeResource SystemBaseMediumColor}" />
|
||||
<TextBlock Text="{Binding Consoles.Count}"
|
||||
FontSize="14"
|
||||
FontWeight="Bold"
|
||||
Foreground="{ThemeResource SystemAccentColor}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Filter Box -->
|
||||
<AutoSuggestBox PlaceholderText="Filter consoles..."
|
||||
Text="{Binding ConsoelsFilterText, Mode=TwoWay}"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{ThemeResource ControlElevationBorderBrush}" />
|
||||
|
||||
<!-- Scrollable Consoles List -->
|
||||
<ScrollViewer Height="200"
|
||||
BorderThickness="1"
|
||||
BorderBrush="{ThemeResource ControlElevationBorderBrush}"
|
||||
CornerRadius="8">
|
||||
<ItemsRepeater ItemsSource="{Binding FilteredConsoles}"
|
||||
Margin="0">
|
||||
<ItemsRepeater.Layout>
|
||||
<StackLayout Spacing="4" />
|
||||
</ItemsRepeater.Layout>
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Button Command="{Binding DataContext.NavigateToMachineCommand, ElementName=PageRoot}"
|
||||
CommandParameter="{Binding}"
|
||||
Padding="12,8"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Left">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="12"
|
||||
TextWrapping="Wrap" />
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Page>
|
||||
77
Marechai.App/Presentation/Views/CompanyDetailPage.xaml.cs
Normal file
77
Marechai.App/Presentation/Views/CompanyDetailPage.xaml.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using Windows.System;
|
||||
using Marechai.App.Presentation.Models;
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class CompanyDetailPage : Page
|
||||
{
|
||||
private object? _navigationSource;
|
||||
private int? _pendingCompanyId;
|
||||
|
||||
public CompanyDetailPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += CompanyDetailPage_DataContextChanged;
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
int? companyId = null;
|
||||
|
||||
// Handle both int and CompanyDetailNavigationParameter
|
||||
if(e.Parameter is int intId)
|
||||
companyId = intId;
|
||||
else if(e.Parameter is CompanyDetailNavigationParameter navParam)
|
||||
{
|
||||
companyId = navParam.CompanyId;
|
||||
_navigationSource = navParam.NavigationSource;
|
||||
}
|
||||
|
||||
if(companyId.HasValue)
|
||||
{
|
||||
_pendingCompanyId = companyId;
|
||||
|
||||
if(DataContext is CompanyDetailViewModel viewModel)
|
||||
{
|
||||
viewModel.CompanyId = companyId.Value;
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CompanyDetailPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(DataContext is CompanyDetailViewModel viewModel && _pendingCompanyId.HasValue)
|
||||
{
|
||||
viewModel.CompanyId = _pendingCompanyId.Value;
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnTwitterClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is CompanyDetailViewModel viewModel && viewModel.Company?.Twitter is not null)
|
||||
{
|
||||
var uri = new Uri($"https://www.twitter.com/{viewModel.Company.Twitter}");
|
||||
await Launcher.LaunchUriAsync(uri);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnFacebookClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is CompanyDetailViewModel viewModel && viewModel.Company?.Facebook is not null)
|
||||
{
|
||||
var uri = new Uri($"https://www.facebook.com/{viewModel.Company.Facebook}");
|
||||
await Launcher.LaunchUriAsync(uri);
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Marechai.App/Presentation/Views/ConsolesListPage.xaml.cs
Normal file
37
Marechai.App/Presentation/Views/ConsolesListPage.xaml.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
/// <summary>
|
||||
/// Professional list view for displaying consoles filtered by letter, year, or all.
|
||||
/// Features responsive layout, modern styling, and smooth navigation.
|
||||
/// </summary>
|
||||
public sealed partial class ConsolesListPage : Page
|
||||
{
|
||||
public ConsolesListPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += ConsolesListPage_Loaded;
|
||||
DataContextChanged += ConsolesListPage_DataContextChanged;
|
||||
}
|
||||
|
||||
private void ConsolesListPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(DataContext is ConsolesListViewModel vm)
|
||||
{
|
||||
// Load data when DataContext is set
|
||||
vm.LoadData.Execute(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void ConsolesListPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is ConsolesListViewModel vm)
|
||||
{
|
||||
// Load data when page is loaded (fallback)
|
||||
vm.LoadData.Execute(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Marechai.App/Presentation/Views/ConsolesPage.xaml.cs
Normal file
44
Marechai.App/Presentation/Views/ConsolesPage.xaml.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using Marechai.App.Presentation.ViewModels;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
|
||||
namespace Marechai.App.Presentation.Views;
|
||||
|
||||
public sealed partial class ConsolesPage : Page
|
||||
{
|
||||
public ConsolesPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += ConsolesPage_DataContextChanged;
|
||||
Loaded += ConsolesPage_Loaded;
|
||||
}
|
||||
|
||||
private void ConsolesPage_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(DataContext is not ConsolesViewModel viewModel) return;
|
||||
|
||||
// Trigger data loading
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
|
||||
private void ConsolesPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
|
||||
{
|
||||
if(args.NewValue is ConsolesViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when data context changes
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
if(DataContext is ConsolesViewModel viewModel)
|
||||
{
|
||||
// Trigger data loading when navigating to the page
|
||||
_ = viewModel.LoadData.ExecuteAsync(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
101
Marechai.App/Services/CompanyDetailService.cs
Normal file
101
Marechai.App/Services/CompanyDetailService.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Marechai.App.Models;
|
||||
|
||||
namespace Marechai.App.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Service for fetching company details from the API
|
||||
/// </summary>
|
||||
public class CompanyDetailService
|
||||
{
|
||||
private readonly ApiClient _apiClient;
|
||||
private readonly ILogger<CompanyDetailService> _logger;
|
||||
|
||||
public CompanyDetailService(ApiClient apiClient, ILogger<CompanyDetailService> logger)
|
||||
{
|
||||
_apiClient = apiClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a single company by ID with full details
|
||||
/// </summary>
|
||||
public async Task<CompanyDto?> GetCompanyByIdAsync(int companyId)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching company {CompanyId} from API", companyId);
|
||||
|
||||
CompanyDto? company = await _apiClient.Companies[companyId].GetAsync();
|
||||
|
||||
if(company == null)
|
||||
{
|
||||
_logger.LogWarning("Company {CompanyId} not found", companyId);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Successfully fetched company {CompanyId}: {CompanyName}", companyId, company.Name);
|
||||
|
||||
return company;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching company {CompanyId} from API", companyId);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets machines (computers) made by a company
|
||||
/// </summary>
|
||||
public async Task<List<MachineDto>> GetComputersByCompanyAsync(int companyId)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching computers for company {CompanyId}", companyId);
|
||||
|
||||
List<MachineDto>? machines = await _apiClient.Companies[companyId].Machines.GetAsync();
|
||||
|
||||
if(machines == null) return [];
|
||||
|
||||
_logger.LogInformation("Successfully fetched {Count} computers for company {CompanyId}", machines.Count, companyId);
|
||||
|
||||
return machines;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching computers for company {CompanyId}", companyId);
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the sold-to company (when company was sold, merged, or renamed)
|
||||
/// </summary>
|
||||
public async Task<CompanyDto?> GetSoldToCompanyAsync(int? companyId)
|
||||
{
|
||||
if(companyId is null or <= 0) return null;
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("Fetching sold-to company {CompanyId}", companyId);
|
||||
|
||||
CompanyDto? company = await _apiClient.Companies[companyId.Value].GetAsync();
|
||||
|
||||
return company;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error fetching sold-to company {CompanyId}", companyId);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,4 +109,61 @@
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Logout</value>
|
||||
</data>
|
||||
<data name="Company is active." xml:space="preserve">
|
||||
<value>Company is active.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on {1}." xml:space="preserve">
|
||||
<value>Company sold to {0} on {1}.</value>
|
||||
</data>
|
||||
<data name="Company sold on {0} to an unknown company." xml:space="preserve">
|
||||
<value>Company sold on {0} to an unknown company.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on an unknown date." xml:space="preserve">
|
||||
<value>Company sold to {0} on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company was sold to an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>Company was sold to an unknown company on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form {1}." xml:space="preserve">
|
||||
<value>Company merged on {0} to form {1}.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form an unknown company." xml:space="preserve">
|
||||
<value>Company merged on {0} to form an unknown company.</value>
|
||||
</data>
|
||||
<data name="Company merged on an unknown date to form {0}." xml:space="preserve">
|
||||
<value>Company merged on an unknown date to form {0}.</value>
|
||||
</data>
|
||||
<data name="Company merged to form an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>Company merged to form an unknown company on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Current company status is unknown." xml:space="preserve">
|
||||
<value>Current company status is unknown.</value>
|
||||
</data>
|
||||
<data name="unknown date" xml:space="preserve">
|
||||
<value>unknown date</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on {0}." xml:space="preserve">
|
||||
<value>Company declared bankruptcy on {0}.</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on an unknown date." xml:space="preserve">
|
||||
<value>Company declared bankruptcy on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on {0}." xml:space="preserve">
|
||||
<value>Company ceased operations on {0}.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on an unknown date." xml:space="preserve">
|
||||
<value>Company ceased operations on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on {1}." xml:space="preserve">
|
||||
<value>Company renamed to {0} on {1}.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on {0} to an unknown name." xml:space="preserve">
|
||||
<value>Company was renamed on {0} to an unknown name.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on an unknown date." xml:space="preserve">
|
||||
<value>Company renamed to {0} on an unknown date.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
|
||||
<value>Company was renamed on an unknown date to an unknown name.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -109,4 +109,61 @@
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Cerrar sesión</value>
|
||||
</data>
|
||||
<data name="Company is active." xml:space="preserve">
|
||||
<value>La empresa está activa.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on {1}." xml:space="preserve">
|
||||
<value>La empresa fue vendida a {0} el {1}.</value>
|
||||
</data>
|
||||
<data name="Company sold on {0} to an unknown company." xml:space="preserve">
|
||||
<value>La empresa fue vendida el {0} a una empresa desconocida.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on an unknown date." xml:space="preserve">
|
||||
<value>La empresa fue vendida a {0} en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company was sold to an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>La empresa fue vendida a una empresa desconocida en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form {1}." xml:space="preserve">
|
||||
<value>La empresa se fusionó el {0} para formar {1}.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form an unknown company." xml:space="preserve">
|
||||
<value>La empresa se fusionó el {0} para formar una empresa desconocida.</value>
|
||||
</data>
|
||||
<data name="Company merged on an unknown date to form {0}." xml:space="preserve">
|
||||
<value>La empresa se fusionó en una fecha desconocida para formar {0}.</value>
|
||||
</data>
|
||||
<data name="Company merged to form an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>La empresa se fusionó para formar una empresa desconocida en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Current company status is unknown." xml:space="preserve">
|
||||
<value>El estado actual de la empresa es desconocido.</value>
|
||||
</data>
|
||||
<data name="unknown date" xml:space="preserve">
|
||||
<value>fecha desconocida</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on {0}." xml:space="preserve">
|
||||
<value>La empresa declaró quiebra el {0}.</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on an unknown date." xml:space="preserve">
|
||||
<value>La empresa declaró quiebra en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on {0}." xml:space="preserve">
|
||||
<value>La empresa cesó operaciones el {0}.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on an unknown date." xml:space="preserve">
|
||||
<value>La empresa cesó operaciones en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on {1}." xml:space="preserve">
|
||||
<value>La empresa fue renombrada a {0} el {1}.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on {0} to an unknown name." xml:space="preserve">
|
||||
<value>La empresa fue renombrada el {0} a un nombre desconocido.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on an unknown date." xml:space="preserve">
|
||||
<value>La empresa fue renombrada a {0} en una fecha desconocida.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
|
||||
<value>La empresa fue renombrada en una fecha desconocida a un nombre desconocido.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -109,4 +109,61 @@
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Déconnexion</value>
|
||||
</data>
|
||||
<data name="Company is active." xml:space="preserve">
|
||||
<value>L'entreprise est active.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on {1}." xml:space="preserve">
|
||||
<value>L'entreprise a été vendue à {0} le {1}.</value>
|
||||
</data>
|
||||
<data name="Company sold on {0} to an unknown company." xml:space="preserve">
|
||||
<value>L'entreprise a été vendue le {0} à une entreprise inconnue.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a été vendue à {0} à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company was sold to an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a été vendue à une entreprise inconnue à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form {1}." xml:space="preserve">
|
||||
<value>L'entreprise a fusionné le {0} pour former {1}.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form an unknown company." xml:space="preserve">
|
||||
<value>L'entreprise a fusionné le {0} pour former une entreprise inconnue.</value>
|
||||
</data>
|
||||
<data name="Company merged on an unknown date to form {0}." xml:space="preserve">
|
||||
<value>L'entreprise a fusionné à une date inconnue pour former {0}.</value>
|
||||
</data>
|
||||
<data name="Company merged to form an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a fusionné pour former une entreprise inconnue à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Current company status is unknown." xml:space="preserve">
|
||||
<value>L'état actuel de l'entreprise est inconnu.</value>
|
||||
</data>
|
||||
<data name="unknown date" xml:space="preserve">
|
||||
<value>date inconnue</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on {0}." xml:space="preserve">
|
||||
<value>L'entreprise a déclaré faillite le {0}.</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a déclaré faillite à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on {0}." xml:space="preserve">
|
||||
<value>L'entreprise a cessé ses activités le {0}.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a cessé ses activités à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on {1}." xml:space="preserve">
|
||||
<value>L'entreprise a été renommée en {0} le {1}.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on {0} to an unknown name." xml:space="preserve">
|
||||
<value>L'entreprise a été renommée le {0} en un nom inconnu.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on an unknown date." xml:space="preserve">
|
||||
<value>L'entreprise a été renommée en {0} à une date inconnue.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
|
||||
<value>L'entreprise a été renommée à une date inconnue en un nom inconnu.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -109,4 +109,61 @@
|
||||
<data name="Logout" xml:space="preserve">
|
||||
<value>Fazer Logout</value>
|
||||
</data>
|
||||
<data name="Company is active." xml:space="preserve">
|
||||
<value>A empresa está ativa.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on {1}." xml:space="preserve">
|
||||
<value>A empresa foi vendida para {0} em {1}.</value>
|
||||
</data>
|
||||
<data name="Company sold on {0} to an unknown company." xml:space="preserve">
|
||||
<value>A empresa foi vendida em {0} para uma empresa desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company sold to {0} on an unknown date." xml:space="preserve">
|
||||
<value>A empresa foi vendida para {0} em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company was sold to an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>A empresa foi vendida para uma empresa desconhecida em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form {1}." xml:space="preserve">
|
||||
<value>A empresa se fundiu em {0} para formar {1}.</value>
|
||||
</data>
|
||||
<data name="Company merged on {0} to form an unknown company." xml:space="preserve">
|
||||
<value>A empresa se fundiu em {0} para formar uma empresa desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company merged on an unknown date to form {0}." xml:space="preserve">
|
||||
<value>A empresa se fundiu em uma data desconhecida para formar {0}.</value>
|
||||
</data>
|
||||
<data name="Company merged to form an unknown company on an unknown date." xml:space="preserve">
|
||||
<value>A empresa se fundiu para formar uma empresa desconhecida em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Current company status is unknown." xml:space="preserve">
|
||||
<value>O status atual da empresa é desconhecido.</value>
|
||||
</data>
|
||||
<data name="unknown date" xml:space="preserve">
|
||||
<value>data desconhecida</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on {0}." xml:space="preserve">
|
||||
<value>A empresa declarou falência em {0}.</value>
|
||||
</data>
|
||||
<data name="Company declared bankruptcy on an unknown date." xml:space="preserve">
|
||||
<value>A empresa declarou falência em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on {0}." xml:space="preserve">
|
||||
<value>A empresa cessou operações em {0}.</value>
|
||||
</data>
|
||||
<data name="Company ceased operations on an unknown date." xml:space="preserve">
|
||||
<value>A empresa cessou operações em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on {1}." xml:space="preserve">
|
||||
<value>A empresa foi renomeada para {0} em {1}.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on {0} to an unknown name." xml:space="preserve">
|
||||
<value>A empresa foi renomeada em {0} para um nome desconhecido.</value>
|
||||
</data>
|
||||
<data name="Company renamed to {0} on an unknown date." xml:space="preserve">
|
||||
<value>A empresa foi renomeada para {0} em uma data desconhecida.</value>
|
||||
</data>
|
||||
<data name="Company was renamed on an unknown date to an unknown name." xml:space="preserve">
|
||||
<value>A empresa foi renomeada em uma data desconhecida para um nome desconhecido.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
Reference in New Issue
Block a user