6db83ccd90
Build and Deploy to Kubernetes / build-and-deploy (push) Failing after 4m55s
- Discount store pages (products, cart, orders, order detail) - Blog pages and services - Payment gateway callback page - AppImage component, EmptyState, LoadingState, PageHeader - DiscountCartService, DiscountOrderService, DiscountProductService - BlogCategoryService, BlogPostService, SitePageService, ImageCacheService - PhoneVerifyForm component - Profile Hub page - UI/UX improvements across all pages - landing.js for homepage - Config and routing updates
205 lines
6.8 KiB
C#
205 lines
6.8 KiB
C#
namespace FrontOffice.Main.Utilities;
|
|
|
|
/// <summary>
|
|
/// Service for fetching published blog posts (customer-facing).
|
|
/// Used by Landing Page (latest posts) and future Blog pages.
|
|
/// </summary>
|
|
public class BlogPostService
|
|
{
|
|
private readonly CMSMicroservice.Protobuf.Protos.BlogPost.BlogPostContract.BlogPostContractClient _client;
|
|
|
|
public BlogPostService(CMSMicroservice.Protobuf.Protos.BlogPost.BlogPostContract.BlogPostContractClient client)
|
|
{
|
|
_client = client;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get featured blog posts (for landing page hero / highlights).
|
|
/// </summary>
|
|
public async Task<List<BlogPostCardDto>> GetFeaturedPostsAsync(int count = 3)
|
|
{
|
|
try
|
|
{
|
|
var response = await _client.GetFeaturedBlogPostsAsync(
|
|
new CMSMicroservice.Protobuf.Protos.BlogPost.GetFeaturedBlogPostsRequest { Count = count });
|
|
|
|
return MapToCardDtos(response?.Models);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
#if DEBUG
|
|
Console.WriteLine($"BlogPostService.GetFeaturedPostsAsync error: {ex.Message}");
|
|
#endif
|
|
return new();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get latest published posts with optional category filter.
|
|
/// </summary>
|
|
public async Task<BlogPostListResult> GetPublishedPostsAsync(int page = 1, int pageSize = 9, string? search = null, long? categoryId = null)
|
|
{
|
|
try
|
|
{
|
|
var request = new CMSMicroservice.Protobuf.Protos.BlogPost.GetPublishedBlogPostsRequest
|
|
{
|
|
PaginationState = new CMSMicroservice.Protobuf.Protos.PaginationState
|
|
{
|
|
PageNumber = page,
|
|
PageSize = pageSize
|
|
}
|
|
};
|
|
|
|
if (!string.IsNullOrWhiteSpace(search))
|
|
request.SearchTerm = search;
|
|
if (categoryId.HasValue)
|
|
request.CategoryId = categoryId.Value;
|
|
|
|
var response = await _client.GetPublishedBlogPostsAsync(request);
|
|
|
|
return new BlogPostListResult
|
|
{
|
|
Posts = MapToCardDtos(response?.Models),
|
|
TotalCount = (int)(response?.MetaData?.TotalCount ?? 0),
|
|
TotalPages = (int)(response?.MetaData?.TotalPage ?? 0),
|
|
CurrentPage = page
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
#if DEBUG
|
|
Console.WriteLine($"BlogPostService.GetPublishedPostsAsync error: {ex.Message}");
|
|
#endif
|
|
return new();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a single blog post by slug (for blog detail page).
|
|
/// </summary>
|
|
public async Task<BlogPostDetailDto?> GetBySlugAsync(string slug)
|
|
{
|
|
try
|
|
{
|
|
var response = await _client.GetBlogPostBySlugAsync(
|
|
new CMSMicroservice.Protobuf.Protos.BlogPost.GetBlogPostBySlugRequest { Slug = slug });
|
|
|
|
if (response == null || response.Id <= 0) return null;
|
|
|
|
return new BlogPostDetailDto
|
|
{
|
|
Id = response.Id,
|
|
Title = response.Title,
|
|
Slug = response.Slug,
|
|
Summary = response.Summary,
|
|
HtmlContent = response.HtmlContent,
|
|
FeaturedImagePath = response.FeaturedImagePath,
|
|
FeaturedImageThumbnailPath = response.FeaturedImageThumbnailPath,
|
|
PublishedAt = response.PublishedAt?.ToDateTime(),
|
|
ViewCount = response.ViewCount,
|
|
IsFeatured = response.IsFeatured,
|
|
Categories = response.Categories?.Select(c => new BlogCategoryInfo { Id = c.Id, Title = c.Title, Slug = c.Slug }).ToList() ?? new(),
|
|
Tags = response.Tags?.Select(t => new BlogTagInfo { Id = t.Id, Title = t.Title, Name = t.Name }).ToList() ?? new()
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
#if DEBUG
|
|
Console.WriteLine($"BlogPostService.GetBySlugAsync error: {ex.Message}");
|
|
#endif
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Increment view count for a blog post.
|
|
/// </summary>
|
|
public async Task IncrementViewCountAsync(long postId)
|
|
{
|
|
try
|
|
{
|
|
await _client.IncrementViewCountAsync(
|
|
new CMSMicroservice.Protobuf.Protos.BlogPost.IncrementViewCountRequest { Id = postId });
|
|
}
|
|
catch
|
|
{
|
|
// Fire and forget — don't fail the page
|
|
}
|
|
}
|
|
|
|
// ── Helpers ──
|
|
|
|
private static List<BlogPostCardDto> MapToCardDtos(
|
|
Google.Protobuf.Collections.RepeatedField<CMSMicroservice.Protobuf.Protos.BlogPost.BlogPostListItem>? models)
|
|
{
|
|
if (models == null || models.Count == 0) return new();
|
|
|
|
return models.Select(m => new BlogPostCardDto
|
|
{
|
|
Id = m.Id,
|
|
Title = m.Title,
|
|
Slug = m.Slug,
|
|
Summary = m.Summary,
|
|
ThumbnailUrl = m.FeaturedImageThumbnailPath,
|
|
PublishedAt = m.PublishedAt?.ToDateTime(),
|
|
ViewCount = m.ViewCount,
|
|
IsFeatured = m.IsFeatured,
|
|
Categories = m.Categories?.Select(c => new BlogCategoryInfo { Id = c.Id, Title = c.Title, Slug = c.Slug }).ToList() ?? new()
|
|
}).ToList();
|
|
}
|
|
|
|
}
|
|
|
|
// ── DTOs ──
|
|
|
|
public class BlogPostCardDto
|
|
{
|
|
public long Id { get; set; }
|
|
public string Title { get; set; } = string.Empty;
|
|
public string Slug { get; set; } = string.Empty;
|
|
public string? Summary { get; set; }
|
|
public string? ThumbnailUrl { get; set; }
|
|
public DateTime? PublishedAt { get; set; }
|
|
public int ViewCount { get; set; }
|
|
public bool IsFeatured { get; set; }
|
|
public List<BlogCategoryInfo> Categories { get; set; } = new();
|
|
}
|
|
|
|
public class BlogPostDetailDto
|
|
{
|
|
public long Id { get; set; }
|
|
public string Title { get; set; } = string.Empty;
|
|
public string Slug { get; set; } = string.Empty;
|
|
public string? Summary { get; set; }
|
|
public string HtmlContent { get; set; } = string.Empty;
|
|
public string? FeaturedImagePath { get; set; }
|
|
public string? FeaturedImageThumbnailPath { get; set; }
|
|
public DateTime? PublishedAt { get; set; }
|
|
public int ViewCount { get; set; }
|
|
public bool IsFeatured { get; set; }
|
|
public List<BlogCategoryInfo> Categories { get; set; } = new();
|
|
public List<BlogTagInfo> Tags { get; set; } = new();
|
|
}
|
|
|
|
public class BlogPostListResult
|
|
{
|
|
public List<BlogPostCardDto> Posts { get; set; } = new();
|
|
public int TotalCount { get; set; }
|
|
public int TotalPages { get; set; }
|
|
public int CurrentPage { get; set; }
|
|
}
|
|
|
|
public class BlogCategoryInfo
|
|
{
|
|
public long Id { get; set; }
|
|
public string Title { get; set; } = string.Empty;
|
|
public string Slug { get; set; } = string.Empty;
|
|
}
|
|
|
|
public class BlogTagInfo
|
|
{
|
|
public long Id { get; set; }
|
|
public string Title { get; set; } = string.Empty;
|
|
public string Name { get; set; } = string.Empty;
|
|
}
|