Files

91 lines
3.3 KiB
C#

using Elternbeirat.Contracts;
using Elternbeirat.PocketBase;
using Elternbeirat.Web.Features.Events;
using Elternbeirat.Web.Shared;
using Microsoft.AspNetCore.Components;
namespace Elternbeirat.Web.Features.Home;
public partial class Home
{
[LoggerMessage(
Level = LogLevel.Warning,
Message = "Could not load the pages for the home page from PocketBase; showing the static title only.")]
private static partial void LogPagesUnavailable(
ILogger logger,
Exception exception);
[LoggerMessage(
Level = LogLevel.Warning,
Message = "Could not load events for the home page from PocketBase; the next-event card is omitted.")]
private static partial void LogEventsUnavailable(
ILogger logger,
Exception exception);
[Inject]
private PocketBaseClient PocketBase { get; set; } = null!;
[Inject]
private ILogger<Home> Logger { get; set; } = null!;
[Inject]
private TimeProvider Time { get; set; } = null!;
[CascadingParameter]
private HttpContext? HttpContext { get; set; }
// Heading, intro and buttons come from the "home" page's body. Until it is loaded
// -- and for good if PocketBase fails during this request -- the static fallback
// heading stands, so the start page always has a title.
private HomeIntro _intro = HomeIntro.Fallback;
// The hero, the tiles and the next-event card are fixed structure of the start
// page; which dynamic blocks follow below is editorial and comes from the "home"
// page's embed field.
private IReadOnlyList<HomeTile> _tiles = [];
private IReadOnlyList<string> _embed = [];
private Event? _nextEvent;
protected override Task OnInitializedAsync()
{
var token = HttpContext?.RequestAborted ?? CancellationToken.None;
return Task.WhenAll(LoadPagesAsync(token), LoadNextEventAsync(token));
}
// Pages and events load side by side and fail on their own: without events the
// page loses only the card, without pages only text and tiles. A PocketBase that
// is plainly down never gets this far -- the maintenance gate in Program.cs
// answers with maintenance.html first. These catches are the second line: the
// gate's health result is cached for a few seconds, so PocketBase can fail between
// that check and these reads. Without them that would be a 500; with them the
// start page stays a 200 rather than a 503 -- degraded, not broken, and rare.
private async Task LoadPagesAsync(CancellationToken token)
{
try
{
var pages = await PocketBase.GetPagesAsync(token);
var home = pages.FirstOrDefault(page => Page.IsHomeSlug(page.Slug));
_intro = HomeIntro.Parse(home?.Body);
_embed = home?.Embed ?? [];
_tiles = HomeTile.From(pages);
}
catch (PocketBaseUnavailableException exception)
{
LogPagesUnavailable(Logger, exception);
}
}
private async Task LoadNextEventAsync(CancellationToken token)
{
try
{
var events = await PocketBase.GetEventsAsync(token);
_nextEvent = UpcomingEvents.From(events, BerlinClock.Today(Time)).FirstOrDefault();
}
catch (PocketBaseUnavailableException exception)
{
LogEventsUnavailable(Logger, exception);
}
}
}