feat(cms): replace home redirect with catalogue dashboard of track/album/genre cards

This commit is contained in:
daniel-c-harvey
2026-06-10 21:35:59 -04:00
parent f8186fb7c7
commit 77dee5eac5
3 changed files with 227 additions and 2 deletions
+102
View File
@@ -440,4 +440,106 @@ public class CmsTrackService : ICmsTrackService
return Result.CreateFailResult("Failed to generate waveform profile.");
}
}
public async Task<ResultContainer<List<AlbumSummaryDto>>> GetAlbumSummariesAsync(CancellationToken ct = default)
{
var client = _httpClientFactory.CreateClient(ContentCmsClientName);
HttpResponseMessage response;
try
{
response = await client.GetAsync("api/track/albums", ct);
}
catch (Exception ex)
{
_logger.LogError(ex, "Content API call failed for album summaries");
return ResultContainer<List<AlbumSummaryDto>>.CreateFailResult("Content API is unreachable.");
}
using (response)
{
if (!response.IsSuccessStatusCode)
{
_logger.LogError("Content API album summaries failed: {Status}", (int)response.StatusCode);
return ResultContainer<List<AlbumSummaryDto>>.CreateFailResult("Failed to load albums.");
}
List<AlbumSummaryDto>? albums;
try
{
albums = await response.Content.ReadFromJsonAsync<List<AlbumSummaryDto>>(ct);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to deserialize album summaries from Content API response");
return ResultContainer<List<AlbumSummaryDto>>.CreateFailResult("Content API returned an unexpected response.");
}
if (albums is null)
{
_logger.LogError("Content API returned a null album summaries list");
return ResultContainer<List<AlbumSummaryDto>>.CreateFailResult("Content API returned an empty response.");
}
return ResultContainer<List<AlbumSummaryDto>>.CreatePassResult(albums);
}
}
public async Task<ResultContainer<List<GenreSummaryDto>>> GetGenreSummariesAsync(CancellationToken ct = default)
{
var client = _httpClientFactory.CreateClient(ContentCmsClientName);
HttpResponseMessage response;
try
{
response = await client.GetAsync("api/track/genres", ct);
}
catch (Exception ex)
{
_logger.LogError(ex, "Content API call failed for genre summaries");
return ResultContainer<List<GenreSummaryDto>>.CreateFailResult("Content API is unreachable.");
}
using (response)
{
if (!response.IsSuccessStatusCode)
{
_logger.LogError("Content API genre summaries failed: {Status}", (int)response.StatusCode);
return ResultContainer<List<GenreSummaryDto>>.CreateFailResult("Failed to load genres.");
}
List<GenreSummaryDto>? genres;
try
{
genres = await response.Content.ReadFromJsonAsync<List<GenreSummaryDto>>(ct);
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to deserialize genre summaries from Content API response");
return ResultContainer<List<GenreSummaryDto>>.CreateFailResult("Content API returned an unexpected response.");
}
if (genres is null)
{
_logger.LogError("Content API returned a null genre summaries list");
return ResultContainer<List<GenreSummaryDto>>.CreateFailResult("Content API returned an empty response.");
}
return ResultContainer<List<GenreSummaryDto>>.CreatePassResult(genres);
}
}
public async Task<ResultContainer<int>> GetTrackCountAsync(CancellationToken ct = default)
{
// Re-use the paged endpoint: a single-item page carries the full TotalCount, so no
// dedicated count endpoint is needed.
var paged = await GetPagedAsync(page: 1, pageSize: 1, sortColumn: null, sortDescending: false, ct);
if (!paged.Success || paged.Value is null)
{
var error = paged.Messages.FirstOrDefault()?.Message ?? "Failed to load track count.";
return ResultContainer<int>.CreateFailResult(error);
}
return ResultContainer<int>.CreatePassResult(paged.Value.TotalCount);
}
}
@@ -82,4 +82,15 @@ public interface ICmsTrackService
/// <c>POST api/track/{entryKey}/waveform</c>. Maps a 404 to a "Track audio not found." failure.
/// </summary>
Task<Result> GenerateWaveformProfileAsync(string entryKey, CancellationToken ct = default);
/// <summary>Returns all distinct albums with track counts from GET api/track/albums.</summary>
Task<ResultContainer<List<AlbumSummaryDto>>> GetAlbumSummariesAsync(CancellationToken ct = default);
/// <summary>Returns all distinct genres with track counts from GET api/track/genres.</summary>
Task<ResultContainer<List<GenreSummaryDto>>> GetGenreSummariesAsync(CancellationToken ct = default);
/// <summary>
/// Returns the total track count by calling GET api/track/page with pageSize=1 and reading TotalCount.
/// </summary>
Task<ResultContainer<int>> GetTrackCountAsync(CancellationToken ct = default);
}