Files
BirthList/src/BirthList.Web/Components/Pages/Home.razor
T
Arne Moerman b59ad6e5ab
Build and Push Docker Image / build-and-push (push) Successful in 27s
Add localization support and UI enhancements
Introduced centralized RESX localization with hierarchical keys for multi-language support. Added resource files for English, French, Dutch (Belgium), and pseudo-localization.

Replaced hardcoded strings in Razor components with localized string references. Added a `PreferredCulture` property to `ApplicationUser` with a migration to store user-specific culture preferences.

Implemented `LocalizationService` to manage supported cultures and user preferences. Added a language picker in `TopBar.razor` and configured `RequestLocalizationOptions` for culture detection.

Localized registry-related components and error messages. Enhanced UI elements to dynamically display localized content. Added pseudo-localization to identify hardcoded strings during development.
2026-05-19 23:30:30 +02:00

175 lines
7.7 KiB
Plaintext

@page "/"
@using BirthList.Web.Features.Registries
<PageTitle>@L["Home.PageTitle"]</PageTitle>
<h1>@L["Home.Welcome"]</h1>
<AuthorizeView>
<Authorized Context="authState">
<div class="registry-sections">
<div class="mb-4">
<div class="section-header">
<h2>@L["Home.ManagedRegistries"]</h2>
<button class="btn btn-primary btn-sm" @onclick="() => ShowCreateForm = !ShowCreateForm">
<span class="bi bi-plus"></span> @L["Home.CreateNew"]
</button>
</div>
@if (MyRegistries.Count == 0)
{
<p class="text-muted">@L["Home.NoRegistries"]</p>
}
else
{
<div class="registry-grid">
@foreach (var registry in MyRegistries)
{
<div class="registry-card">
<h3>@registry.Title</h3>
<div class="registry-actions">
<a href="/registry/@registry.PublicLinkCode" class="btn btn-outline-primary btn-sm">@L["Home.View"]</a>
<a href="/registry/@registry.Id/admin" class="btn btn-outline-secondary btn-sm">@L["Home.Manage"]</a>
</div>
</div>
}
</div>
}
</div>
<div class="mb-4">
<h2>@L["Home.VisitedRegistries"]</h2>
@if (VisitedRegistries.Count == 0)
{
<p class="text-muted">@L["Home.NoVisitedRegistries"]</p>
}
else
{
<div class="registry-grid">
@foreach (var registry in VisitedRegistries)
{
<div class="registry-card">
<h3>@registry.Title</h3>
<div class="registry-actions">
<a href="/registry/@registry.PublicLinkCode" class="btn btn-outline-primary btn-sm">@L["Home.View"]</a>
</div>
</div>
}
</div>
}
</div>
</div>
@if (ShowCreateForm)
{
<div class="create-registry-modal-overlay" @onclick="() => ShowCreateForm = false">
<div class="create-registry-modal" @onclick:stopPropagation="true">
<div class="modal-header">
<h3 class="modal-title">@L["Home.CreateRegistryTitle"]</h3>
<button type="button" class="btn-close" @onclick="() => ShowCreateForm = false"></button>
</div>
<div class="modal-body">
<EditForm Model="Model" OnValidSubmit="CreateRegistryAsync" Context="formContext" FormName="create-registry-form">
<DataAnnotationsValidator />
<div class="mb-3">
<label class="form-label">@L["Home.Title"]</label>
<InputText class="form-control" @bind-Value="Model.Title" />
</div>
<div class="mb-3">
<label class="form-label">@L["Home.Type"]</label>
<InputSelect class="form-select" @bind-Value="Model.RegistryType">
<option value="@BirthList.Domain.Entities.RegistryType.Birth">@L["Home.RegistryType.Birth"]</option>
<option value="@BirthList.Domain.Entities.RegistryType.Wedding">@L["Home.RegistryType.Wedding"]</option>
<option value="@BirthList.Domain.Entities.RegistryType.Birthday">@L["Home.RegistryType.Birthday"]</option>
</InputSelect>
</div>
<div class="mb-3">
<label class="form-label">@L["Home.Theme"]</label>
<InputSelect class="form-select" @bind-Value="Model.ThemeKey">
<option value="default">@L["Home.Theme.Default"]</option>
<option value="soft">@L["Home.Theme.Soft"]</option>
<option value="modern">@L["Home.Theme.Modern"]</option>
</InputSelect>
</div>
@if (!string.IsNullOrWhiteSpace(ErrorMessage))
{
<div class="alert alert-danger mb-3">@ErrorMessage</div>
}
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" @onclick="() => ShowCreateForm = false">@L["Common.Cancel"]</button>
<button class="btn btn-primary" type="submit">@L["Home.CreateNew"]</button>
</div>
</EditForm>
</div>
</div>
</div>
}
</Authorized>
<NotAuthorized>
<div class="alert alert-info mt-4">
<p>
@L["Home.LoginPromptPrefix"]<a href="Account/Login">@L["Home.LoginPromptLinkText"]</a>@L["Home.LoginPromptSuffix"]
</p>
</div>
</NotAuthorized>
</AuthorizeView>
@code {
[SupplyParameterFromForm(FormName = "create-registry-form")]
protected RegistryCreateModel Model { get; set; } = new();
protected IReadOnlyList<RegistrySummaryViewModel> MyRegistries { get; private set; } = [];
protected IReadOnlyList<RegistrySummaryViewModel> VisitedRegistries { get; private set; } = [];
protected string? ErrorMessage { get; private set; }
protected bool ShowCreateForm { get; private set; }
[Inject] private RegistryService RegistryService { get; set; } = null!;
[Inject] private RegistryUserContext RegistryUserContext { get; set; } = null!;
protected override async Task OnInitializedAsync()
{
await LoadAsync().ConfigureAwait(false);
}
protected async Task CreateRegistryAsync()
{
ErrorMessage = null;
var userId = await RegistryUserContext.GetUserIdAsync(CancellationToken.None).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(userId))
{
ErrorMessage = L["Home.MustBeLoggedIn"];
return;
}
if (string.IsNullOrWhiteSpace(Model.Title))
{
ErrorMessage = L["Home.TitleRequired"];
return;
}
await RegistryService.CreateRegistryAsync(userId, Model, CancellationToken.None).ConfigureAwait(false);
Model = new RegistryCreateModel
{
RegistryType = Model.RegistryType,
ThemeKey = Model.ThemeKey
};
ShowCreateForm = false;
await LoadAsync().ConfigureAwait(false);
}
private async Task LoadAsync()
{
var userId = await RegistryUserContext.GetUserIdAsync(CancellationToken.None).ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(userId))
{
MyRegistries = [];
VisitedRegistries = [];
return;
}
MyRegistries = await RegistryService.GetAdminRegistriesAsync(userId, CancellationToken.None).ConfigureAwait(false);
VisitedRegistries = await RegistryService.GetVisitedRegistriesAsync(userId, CancellationToken.None).ConfigureAwait(false);
}
}