Init
This commit is contained in:
32
Prefab.Web.Client/Services/HomePageService.cs
Normal file
32
Prefab.Web.Client/Services/HomePageService.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using Prefab.Web.Client.Models.Home;
|
||||
using Prefab.Web.Client.Models.Shared;
|
||||
|
||||
namespace Prefab.Web.Client.Services;
|
||||
|
||||
public interface IHomePageService
|
||||
{
|
||||
Task<Result<HomePageModel>> Get(CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public sealed class HomePageService(HttpClient httpClient) : IHomePageService
|
||||
{
|
||||
public async Task<Result<HomePageModel>> Get(CancellationToken cancellationToken)
|
||||
{
|
||||
using var response = await httpClient.GetAsync("bff/home", cancellationToken);
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<Result<HomePageModel>>(cancellationToken: cancellationToken);
|
||||
|
||||
if (result is not null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var status = (HttpStatusCode)response.StatusCode;
|
||||
var exception = new InvalidOperationException($"Response {(int)status} did not contain a valid payload.");
|
||||
var problem = ResultProblem.Unexpected("Failed to retrieve home page content.", exception, status);
|
||||
|
||||
return Result<HomePageModel>.Failure(problem);
|
||||
}
|
||||
}
|
||||
30
Prefab.Web.Client/Services/ICategoriesPageService.cs
Normal file
30
Prefab.Web.Client/Services/ICategoriesPageService.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Net.Http.Json;
|
||||
using Prefab.Web.Client.Models.Shared;
|
||||
using Prefab.Web.Client.Pages;
|
||||
|
||||
namespace Prefab.Web.Client.Services;
|
||||
|
||||
public interface ICategoriesPageService
|
||||
{
|
||||
Task<Result<CategoriesPageModel>> GetPage(CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public sealed class CategoriesPageService(HttpClient httpClient) : ICategoriesPageService
|
||||
{
|
||||
public async Task<Result<CategoriesPageModel>> GetPage(CancellationToken cancellationToken)
|
||||
{
|
||||
using var response = await httpClient.GetAsync("bff/categories/page", cancellationToken);
|
||||
|
||||
var result = await response.Content.ReadFromJsonAsync<Result<CategoriesPageModel>>(cancellationToken);
|
||||
|
||||
if (result is not null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var exception = new InvalidOperationException($"Response {(int)response.StatusCode} did not contain a valid payload.");
|
||||
var unexpectedProblem = ResultProblem.Unexpected("Failed to retrieve categories.", exception, response.StatusCode);
|
||||
|
||||
return Result<CategoriesPageModel>.Failure(unexpectedProblem);
|
||||
}
|
||||
}
|
||||
60
Prefab.Web.Client/Services/INavMenuService.cs
Normal file
60
Prefab.Web.Client/Services/INavMenuService.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using Prefab.Web.Client.Models.Shared;
|
||||
|
||||
namespace Prefab.Web.Client.Services;
|
||||
|
||||
public interface INavMenuService
|
||||
{
|
||||
Task<Result<NavMenuModel>> Get(int depth, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public sealed class NavMenuService : INavMenuService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
|
||||
public NavMenuService(HttpClient httpClient)
|
||||
{
|
||||
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
||||
}
|
||||
|
||||
public async Task<Result<NavMenuModel>> Get(int depth, CancellationToken cancellationToken)
|
||||
{
|
||||
var normalizedDepth = Math.Clamp(depth, 1, 2);
|
||||
|
||||
try
|
||||
{
|
||||
using var response = await _httpClient.GetAsync($"/bff/nav-menu/{normalizedDepth}", cancellationToken);
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<Result<NavMenuModel>>(cancellationToken: cancellationToken);
|
||||
|
||||
if (payload is not null)
|
||||
{
|
||||
return payload;
|
||||
}
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var statusCode = (HttpStatusCode)response.StatusCode;
|
||||
var problem = ResultProblem.Unexpected(
|
||||
"Failed to load navigation menu.",
|
||||
new HttpRequestException($"Navigation menu request failed with status code {(int)statusCode} ({statusCode})."),
|
||||
statusCode);
|
||||
|
||||
return Result<NavMenuModel>.Failure(problem);
|
||||
}
|
||||
|
||||
var emptyProblem = ResultProblem.Unexpected(
|
||||
"Failed to load navigation menu.",
|
||||
new InvalidOperationException("Navigation menu response body was empty."),
|
||||
(HttpStatusCode)response.StatusCode);
|
||||
|
||||
return Result<NavMenuModel>.Failure(emptyProblem);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
var problem = ResultProblem.Unexpected("Failed to load navigation menu.", exception);
|
||||
return Result<NavMenuModel>.Failure(problem);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Prefab.Web.Client/Services/INotificationService.cs
Normal file
78
Prefab.Web.Client/Services/INotificationService.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using Telerik.Blazor;
|
||||
using Telerik.Blazor.Components;
|
||||
|
||||
namespace Prefab.Web.Client.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Defines a contract for displaying notifications of various types, such as errors, successes, and warnings, within an
|
||||
/// application.
|
||||
/// </summary>
|
||||
/// <remarks>Implementations of this interface provide methods to present user-facing messages in a consistent
|
||||
/// manner. The interface supports attaching a notification component and displaying messages with different severity
|
||||
/// levels. This is typically used to inform users about the outcome of operations or to alert them to important
|
||||
/// events.</remarks>
|
||||
public interface INotificationService
|
||||
{
|
||||
void Attach(TelerikNotification notification);
|
||||
void ShowError(string message);
|
||||
void ShowSuccess(string message);
|
||||
void ShowWarning(string message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides functionality to display error, success, and warning notifications using a Telerik notification component.
|
||||
/// </summary>
|
||||
/// <remarks>This service queues notifications if the Telerik notification component is not yet attached, and
|
||||
/// displays them once the component becomes available. It is intended to be used as an abstraction for showing
|
||||
/// user-facing notifications in applications that utilize Telerik UI components.</remarks>
|
||||
public class NotificationService : INotificationService
|
||||
{
|
||||
private readonly Queue<NotificationModel> _pending = new();
|
||||
private TelerikNotification? _notification;
|
||||
|
||||
public void Attach(TelerikNotification notification)
|
||||
{
|
||||
_notification = notification ?? throw new ArgumentNullException(nameof(notification));
|
||||
FlushPending();
|
||||
}
|
||||
|
||||
public void ShowError(string message) =>
|
||||
Show(message, ThemeConstants.Notification.ThemeColor.Error);
|
||||
|
||||
public void ShowSuccess(string message) =>
|
||||
Show(message, ThemeConstants.Notification.ThemeColor.Success);
|
||||
|
||||
public void ShowWarning(string message) =>
|
||||
Show(message, ThemeConstants.Notification.ThemeColor.Warning);
|
||||
|
||||
private void Show(string message, string themeColor)
|
||||
{
|
||||
var model = new NotificationModel
|
||||
{
|
||||
Text = message,
|
||||
ThemeColor = themeColor,
|
||||
CloseAfter = 3000
|
||||
};
|
||||
|
||||
if (_notification is { } notification)
|
||||
{
|
||||
notification.Show(model);
|
||||
return;
|
||||
}
|
||||
|
||||
_pending.Enqueue(model);
|
||||
}
|
||||
|
||||
private void FlushPending()
|
||||
{
|
||||
if (_notification is not { } notification)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (_pending.Count > 0)
|
||||
{
|
||||
notification.Show(_pending.Dequeue());
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Prefab.Web.Client/Services/IProductListingService.cs
Normal file
37
Prefab.Web.Client/Services/IProductListingService.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using Prefab.Web.Client.Models.Catalog;
|
||||
using Prefab.Web.Client.Models.Shared;
|
||||
|
||||
namespace Prefab.Web.Client.Services;
|
||||
|
||||
public interface IProductListingService
|
||||
{
|
||||
Task<Result<ProductListingModel>> GetCategoryProducts(string categorySlug, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public sealed class ProductListingService(HttpClient httpClient) : IProductListingService
|
||||
{
|
||||
public async Task<Result<ProductListingModel>> GetCategoryProducts(string categorySlug, CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(categorySlug);
|
||||
|
||||
using var response = await httpClient.GetAsync(
|
||||
$"/bff/catalog/categories/{Uri.EscapeDataString(categorySlug)}" +
|
||||
"/models",
|
||||
cancellationToken);
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<Result<ProductListingModel>>(cancellationToken: cancellationToken);
|
||||
|
||||
if (payload is not null)
|
||||
{
|
||||
return payload;
|
||||
}
|
||||
|
||||
var statusCode = (HttpStatusCode)response.StatusCode;
|
||||
var exception = new InvalidOperationException($"Response {(int)statusCode} did not contain a valid payload.");
|
||||
var unexpectedProblem = ResultProblem.Unexpected("Failed to retrieve category products.", exception, statusCode);
|
||||
|
||||
return Result<ProductListingModel>.Failure(unexpectedProblem);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user