- Update NavMenu to show "Samples" instead of "Home" - Add ReceiverLayout.razor for receiver-facing pages: - Includes main content, sticky footer, and privacy link - Implements cookie consent banner using localStorage - Adds language switcher with LocalizationService integration - Handles event disposal and JS interop for SSR/client scenarios
117 lines
3.7 KiB
Plaintext
117 lines
3.7 KiB
Plaintext
@inherits LayoutComponentBase
|
|
@implements IDisposable
|
|
@inject LocalizationService Loc
|
|
@inject NavigationManager Nav
|
|
@inject IJSRuntime JS
|
|
|
|
@*
|
|
Layout for the receiver-facing pages migrated from EnvelopeGenerator.Web.
|
|
Mirrors the legacy MVC <body> structure: page content + sticky footer
|
|
with copyright link, language switcher and privacy link.
|
|
|
|
Cookie consent is reimplemented in Blazor (localStorage-backed) because
|
|
ASP.NET Core's <ITrackingConsentFeature> only works on the server side
|
|
and is awkward to integrate with InteractiveAuto rendering.
|
|
*@
|
|
|
|
<div class="receiver-shell">
|
|
|
|
@* Main page content *@
|
|
<main role="main" class="flex-grow-1">
|
|
@Body
|
|
</main>
|
|
|
|
@* Cookie consent banner (Blazor counterpart of _CookieConsentPartial). *@
|
|
@if (_consentVisible)
|
|
{
|
|
<div class="receiver-cookie-banner" role="alertdialog" aria-live="polite">
|
|
<span>@Loc["CookieConsentMessage"]</span>
|
|
<DxButton Text="@Loc["Accept"]"
|
|
RenderStyle="ButtonRenderStyle.Primary"
|
|
Click="AcceptCookiesAsync" />
|
|
</div>
|
|
}
|
|
|
|
@* Footer (copyright + language switcher + privacy). *@
|
|
<footer class="receiver-footer">
|
|
<span>
|
|
© SignFlow 2023-@DateTime.Now.Year
|
|
<a href="https://digitaldata.works" target="_blank" rel="noopener">Digital Data GmbH</a>
|
|
</span>
|
|
|
|
<div class="d-flex align-items-center gap-2">
|
|
<select class="language-switcher" value="@_currentLang" @onchange="OnLanguageChangedAsync">
|
|
@foreach (var (lang, native, _) in LocalizationService.SupportedLanguages)
|
|
{
|
|
<option value="@lang" selected="@(lang == _currentLang)">@native</option>
|
|
}
|
|
</select>
|
|
</div>
|
|
|
|
<a href="@($"/privacy-policy.{_currentLang}.html")" target="_blank" rel="noopener">
|
|
@Loc["Privacy"]
|
|
</a>
|
|
</footer>
|
|
</div>
|
|
|
|
@code {
|
|
private string _currentLang = "de";
|
|
private bool _consentVisible;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
Loc.Changed += OnLocChanged;
|
|
await Loc.EnsureLoadedAsync();
|
|
_currentLang = Loc.CurrentLanguage ?? "de";
|
|
}
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
if (!firstRender) return;
|
|
// Probe localStorage on the client only — InteractiveAuto means
|
|
// the server prerender runs without a browser, so JS interop is
|
|
// unavailable until the first client render.
|
|
try
|
|
{
|
|
var accepted = await JS.InvokeAsync<string?>("localStorage.getItem", "receiver.cookie-consent");
|
|
_consentVisible = accepted != "1";
|
|
StateHasChanged();
|
|
}
|
|
catch
|
|
{
|
|
// No-op: server prerender (JS unavailable) keeps the banner hidden.
|
|
}
|
|
}
|
|
|
|
private async Task AcceptCookiesAsync()
|
|
{
|
|
try
|
|
{
|
|
await JS.InvokeVoidAsync("localStorage.setItem", "receiver.cookie-consent", "1");
|
|
}
|
|
catch { /* ignore */ }
|
|
_consentVisible = false;
|
|
}
|
|
|
|
private async Task OnLanguageChangedAsync(ChangeEventArgs e)
|
|
{
|
|
var code = e.Value?.ToString();
|
|
if (string.IsNullOrEmpty(code) || code == _currentLang)
|
|
return;
|
|
|
|
_currentLang = code;
|
|
await Loc.ChangeLanguageAsync(code);
|
|
// Force a full reload so ASP.NET Core localization middleware
|
|
// picks up the new culture for any subsequent SSR / API calls.
|
|
Nav.NavigateTo(Nav.Uri, forceLoad: true);
|
|
}
|
|
|
|
private void OnLocChanged()
|
|
{
|
|
_currentLang = Loc.CurrentLanguage ?? _currentLang;
|
|
InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
public void Dispose() => Loc.Changed -= OnLocChanged;
|
|
}
|