Add computer list.

This commit is contained in:
2025-11-15 01:09:30 +00:00
parent b18396f8d8
commit 61ebf7b503
7 changed files with 169 additions and 46 deletions

View File

@@ -102,6 +102,12 @@ public partial class App : Application
services.AddSingleton<NewsViewModel>(); services.AddSingleton<NewsViewModel>();
services.AddSingleton<ComputersService>(); services.AddSingleton<ComputersService>();
services.AddSingleton<ComputersViewModel>(); services.AddSingleton<ComputersViewModel>();
services
.AddSingleton<IComputersListFilterContext,
ComputersListFilterContext>();
services.AddTransient<ComputersListViewModel>();
}) })
.UseNavigation(RegisterRoutes)); .UseNavigation(RegisterRoutes));
@@ -121,6 +127,7 @@ public partial class App : Application
new ViewMap<MainPage, MainViewModel>(), new ViewMap<MainPage, MainViewModel>(),
new ViewMap<NewsPage, NewsViewModel>(), new ViewMap<NewsPage, NewsViewModel>(),
new ViewMap<ComputersPage, ComputersViewModel>(), new ViewMap<ComputersPage, ComputersViewModel>(),
new ViewMap<ComputersListPage, ComputersListViewModel>(),
new DataViewMap<SecondPage, SecondViewModel, Entity>()); new DataViewMap<SecondPage, SecondViewModel, Entity>());
routes.Register(new RouteMap("", routes.Register(new RouteMap("",
@@ -136,7 +143,13 @@ public partial class App : Application
views.FindByViewModel<NewsViewModel>(), views.FindByViewModel<NewsViewModel>(),
true), true),
new RouteMap("computers", new RouteMap("computers",
views.FindByViewModel<ComputersViewModel>()), views.FindByViewModel<ComputersViewModel>(),
Nested:
[
new RouteMap("list",
views.FindByViewModel<
ComputersListViewModel>())
]),
new RouteMap("Second", new RouteMap("Second",
views.FindByViewModel<SecondViewModel>()) views.FindByViewModel<SecondViewModel>())
]) ])

View File

@@ -10,6 +10,7 @@ namespace Marechai.App.Presentation;
public partial class ComputersViewModel : ObservableObject public partial class ComputersViewModel : ObservableObject
{ {
private readonly ComputersService _computersService; private readonly ComputersService _computersService;
private readonly IComputersListFilterContext _filterContext;
private readonly IStringLocalizer _localizer; private readonly IStringLocalizer _localizer;
private readonly ILogger<ComputersViewModel> _logger; private readonly ILogger<ComputersViewModel> _logger;
private readonly INavigator _navigator; private readonly INavigator _navigator;
@@ -48,12 +49,14 @@ public partial class ComputersViewModel : ObservableObject
private ObservableCollection<int> yearsList = new(); private ObservableCollection<int> yearsList = new();
public ComputersViewModel(ComputersService computersService, IStringLocalizer localizer, public ComputersViewModel(ComputersService computersService, IStringLocalizer localizer,
ILogger<ComputersViewModel> logger, INavigator navigator) ILogger<ComputersViewModel> logger, INavigator navigator,
IComputersListFilterContext filterContext)
{ {
_computersService = computersService; _computersService = computersService;
_localizer = localizer; _localizer = localizer;
_logger = logger; _logger = logger;
_navigator = navigator; _navigator = navigator;
_filterContext = filterContext;
LoadData = new AsyncRelayCommand(LoadDataAsync); LoadData = new AsyncRelayCommand(LoadDataAsync);
GoBackCommand = new AsyncRelayCommand(GoBackAsync); GoBackCommand = new AsyncRelayCommand(GoBackAsync);
NavigateByLetterCommand = new AsyncRelayCommand<char>(NavigateByLetterAsync); NavigateByLetterCommand = new AsyncRelayCommand<char>(NavigateByLetterAsync);
@@ -146,32 +149,59 @@ public partial class ComputersViewModel : ObservableObject
/// Navigates to computers filtered by letter /// Navigates to computers filtered by letter
/// </summary> /// </summary>
private async Task NavigateByLetterAsync(char letter) private async Task NavigateByLetterAsync(char letter)
{
try
{ {
_logger.LogInformation("Navigating to computers by letter: {Letter}", letter); _logger.LogInformation("Navigating to computers by letter: {Letter}", letter);
_filterContext.FilterType = ComputerListFilterType.Letter;
// TODO: Implement navigation to letter-filtered view _filterContext.FilterValue = letter.ToString();
await Task.CompletedTask; await _navigator.NavigateViewModelAsync<ComputersListViewModel>(this);
}
catch(Exception ex)
{
_logger.LogError("Error navigating to letter computers: {Exception}", ex.Message);
ErrorMessage = _localizer["Failed to navigate. Please try again."].Value;
HasError = true;
}
} }
/// <summary> /// <summary>
/// Navigates to computers filtered by year /// Navigates to computers filtered by year
/// </summary> /// </summary>
private async Task NavigateByYearAsync(int year) private async Task NavigateByYearAsync(int year)
{
try
{ {
_logger.LogInformation("Navigating to computers by year: {Year}", year); _logger.LogInformation("Navigating to computers by year: {Year}", year);
_filterContext.FilterType = ComputerListFilterType.Year;
// TODO: Implement navigation to year-filtered view _filterContext.FilterValue = year.ToString();
await Task.CompletedTask; await _navigator.NavigateViewModelAsync<ComputersListViewModel>(this);
}
catch(Exception ex)
{
_logger.LogError("Error navigating to year computers: {Exception}", ex.Message);
ErrorMessage = _localizer["Failed to navigate. Please try again."].Value;
HasError = true;
}
} }
/// <summary> /// <summary>
/// Navigates to all computers view /// Navigates to all computers view
/// </summary> /// </summary>
private async Task NavigateAllComputersAsync() private async Task NavigateAllComputersAsync()
{
try
{ {
_logger.LogInformation("Navigating to all computers"); _logger.LogInformation("Navigating to all computers");
_filterContext.FilterType = ComputerListFilterType.All;
// TODO: Implement navigation to all computers view _filterContext.FilterValue = string.Empty;
await Task.CompletedTask; await _navigator.NavigateViewModelAsync<ComputersListViewModel>(this);
}
catch(Exception ex)
{
_logger.LogError("Error navigating to all computers: {Exception}", ex.Message);
ErrorMessage = _localizer["Failed to navigate. Please try again."].Value;
HasError = true;
}
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Kiota.Abstractions.Serialization; using Microsoft.Kiota.Abstractions.Serialization;
@@ -118,4 +119,81 @@ public class ComputersService
return 0; return 0;
} }
} }
/// <summary>
/// Fetches computers filtered by starting letter from the API
/// </summary>
public async Task<List<MachineDto>> GetComputersByLetterAsync(char letter)
{
try
{
_logger.LogInformation("Fetching computers starting with '{Letter}' from API", letter);
List<MachineDto> computers = await _apiClient.Computers.ByLetter[letter.ToString()].GetAsync();
if(computers == null) return new List<MachineDto>();
_logger.LogInformation("Successfully fetched {Count} computers starting with '{Letter}'",
computers.Count,
letter);
return computers;
}
catch(Exception ex)
{
_logger.LogError(ex, "Error fetching computers by letter '{Letter}' from API", letter);
return new List<MachineDto>();
}
}
/// <summary>
/// Fetches computers filtered by year from the API
/// </summary>
public async Task<List<MachineDto>> GetComputersByYearAsync(int year)
{
try
{
_logger.LogInformation("Fetching computers from year {Year} from API", year);
List<MachineDto> computers = await _apiClient.Computers.ByYear[year].GetAsync();
if(computers == null) return new List<MachineDto>();
_logger.LogInformation("Successfully fetched {Count} computers from year {Year}", computers.Count, year);
return computers;
}
catch(Exception ex)
{
_logger.LogError(ex, "Error fetching computers by year {Year} from API", year);
return new List<MachineDto>();
}
}
/// <summary>
/// Fetches all computers from the API
/// </summary>
public async Task<List<MachineDto>> GetAllComputersAsync()
{
try
{
_logger.LogInformation("Fetching all computers from API");
List<MachineDto> computers = await _apiClient.Computers.GetAsync();
if(computers == null) return new List<MachineDto>();
_logger.LogInformation("Successfully fetched {Count} total computers", computers.Count);
return computers;
}
catch(Exception ex)
{
_logger.LogError(ex, "Error fetching all computers from API");
return new List<MachineDto>();
}
}
} }

View File

@@ -3,6 +3,7 @@
"Environment": "Production" "Environment": "Production"
}, },
"ApiClient": { "ApiClient": {
"Url": "http://localhost:5023",
"UseNativeHandler": true "UseNativeHandler": true
}, },
"LocalizationConfiguration": { "LocalizationConfiguration": {

View File

@@ -80,7 +80,8 @@ public class ComputersController(MarechaiContext context) : ControllerBase
{ {
Id = m.Id, Id = m.Id,
Name = m.Name, Name = m.Name,
Company = m.Company.Name Company = m.Company.Name,
Introduced = m.Introduced
}) })
.ToListAsync(); .ToListAsync();
@@ -99,7 +100,8 @@ public class ComputersController(MarechaiContext context) : ControllerBase
{ {
Id = m.Id, Id = m.Id,
Name = m.Name, Name = m.Name,
Company = m.Company.Name Company = m.Company.Name,
Introduced = m.Introduced
}) })
.ToListAsync(); .ToListAsync();
@@ -115,7 +117,8 @@ public class ComputersController(MarechaiContext context) : ControllerBase
{ {
Id = m.Id, Id = m.Id,
Name = m.Name, Name = m.Name,
Company = m.Company.Name Company = m.Company.Name,
Introduced = m.Introduced
}) })
.ToListAsync(); .ToListAsync();
} }

View File

@@ -80,7 +80,8 @@ public class ConsolesController(MarechaiContext context) : ControllerBase
{ {
Id = m.Id, Id = m.Id,
Name = m.Name, Name = m.Name,
Company = m.Company.Name Company = m.Company.Name,
Introduced = m.Introduced
}) })
.ToListAsync(); .ToListAsync();
@@ -99,7 +100,8 @@ public class ConsolesController(MarechaiContext context) : ControllerBase
{ {
Id = m.Id, Id = m.Id,
Name = m.Name, Name = m.Name,
Company = m.Company.Name Company = m.Company.Name,
Introduced = m.Introduced
}) })
.ToListAsync(); .ToListAsync();
@@ -115,7 +117,8 @@ public class ConsolesController(MarechaiContext context) : ControllerBase
{ {
Id = m.Id, Id = m.Id,
Name = m.Name, Name = m.Name,
Company = m.Company.Name Company = m.Company.Name,
Introduced = m.Introduced
}) })
.ToListAsync(); .ToListAsync();
} }

View File

@@ -210,24 +210,19 @@ file class Program
builder.Services.AddScoped<TokenService, TokenService>(); builder.Services.AddScoped<TokenService, TokenService>();
// Read allowed CORS origins from configuration // Read allowed CORS origins from configuration
string[] allowedOrigins = builder.Configuration.GetSection("CORS:AllowedOrigins").Get<string[]>(); string[] allowedOrigins = builder.Configuration.GetSection("CORS:AllowedOrigins").Get<string[]>() ??
Array.Empty<string>();
builder.Services.AddCors(options => builder.Services.AddCors(options =>
{ {
options.AddPolicy("AllowFrontend", options.AddPolicy("AllowFrontend",
policy => policy =>
{ {
switch(allowedOrigins) // Check if wildcard is in the allowed origins
{ if(allowedOrigins.Contains("*"))
case ["*"]:
policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod(); policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
else if(allowedOrigins.Length > 0)
break;
case { Length: > 0 }:
policy.WithOrigins(allowedOrigins).AllowAnyHeader().AllowAnyMethod(); policy.WithOrigins(allowedOrigins).AllowAnyHeader().AllowAnyMethod();
break;
}
}); });
}); });