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 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 is down -- 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 _tiles = []; private IReadOnlyList _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. Either way the // start page stays a 200 rather than a 503 -- it is degraded, not broken. 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); } } }