3418d1a46c
PR Checks / test-and-build (pull_request) Successful in 12m47s
Add publication settings for clubs and sessions, read-only public club/session pages, dashboard controls, privacy-focused public queries, docs, and tests. Bump version to 3.3.0
122 lines
4.4 KiB
Plaintext
122 lines
4.4 KiB
Plaintext
@page "/club/{Slug}"
|
|
@layout PublicLayout
|
|
@inject ISessionStore SessionStore
|
|
@inject NavigationManager Navigation
|
|
|
|
<PageTitle>@PageTitleText</PageTitle>
|
|
|
|
@if (loaded && club is null)
|
|
{
|
|
<HeadContent>
|
|
<meta name="robots" content="noindex, nofollow" />
|
|
</HeadContent>
|
|
|
|
<section class="public-hero public-hero-compact">
|
|
<span class="status-badge status-neutral">Недоступно</span>
|
|
<h1>Публичная страница не найдена</h1>
|
|
<p>Расписание клуба выключено или адрес больше не используется.</p>
|
|
</section>
|
|
}
|
|
else if (!loaded)
|
|
{
|
|
<section class="public-hero public-hero-compact">
|
|
<div class="skeleton skeleton-text" style="width: 55%; height: 2rem;"></div>
|
|
<div class="skeleton skeleton-text" style="width: 75%;"></div>
|
|
</section>
|
|
}
|
|
else if (club is not null)
|
|
{
|
|
<HeadContent>
|
|
<meta name="description" content="@($"Публичное расписание клуба {club.Name} в GM-Relay.")" />
|
|
</HeadContent>
|
|
|
|
<section class="public-hero">
|
|
<span class="status-badge status-success">Публичное расписание</span>
|
|
<h1>@club.Name</h1>
|
|
<p>Открытые игры клуба без состава игроков, личных данных и приватных ссылок.</p>
|
|
<div class="public-share-row">
|
|
<span>Ссылка клуба</span>
|
|
<a href="@PublicClubUrl" target="_blank" rel="noopener noreferrer">@PublicClubUrl</a>
|
|
</div>
|
|
</section>
|
|
|
|
@if (club.Sessions.Count == 0)
|
|
{
|
|
<div class="glass-card public-empty-state">
|
|
<h2>Опубликованных игр пока нет</h2>
|
|
<p>Когда owner или co-GM откроет сессии для публичного расписания, они появятся здесь.</p>
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
<div class="public-session-list">
|
|
@foreach (var session in club.Sessions)
|
|
{
|
|
<article class="public-session-card">
|
|
<div class="public-session-main">
|
|
<span class="status-badge @GetStatusClass(session.Status)">@TranslateStatus(session.Status)</span>
|
|
<h2>@session.Title</h2>
|
|
<div class="public-session-meta">
|
|
<span>@session.ScheduledAt.FormatMoscow()</span>
|
|
<span>@FormatSeats(session)</span>
|
|
</div>
|
|
</div>
|
|
<a class="btn-gm btn-gm-outline" href="@PublicSessionPath(session.Id)">Открыть</a>
|
|
</article>
|
|
}
|
|
</div>
|
|
}
|
|
}
|
|
|
|
@code {
|
|
[Parameter] public string? Slug { get; set; }
|
|
|
|
private WebPublicClub? club;
|
|
private bool loaded;
|
|
|
|
private string PageTitleText => club is null ? "Публичный клуб — GM-Relay" : $"{club.Name} — GM-Relay";
|
|
|
|
private string PublicClubUrl =>
|
|
club is null
|
|
? Navigation.ToAbsoluteUri($"/club/{Slug}").ToString()
|
|
: Navigation.ToAbsoluteUri($"/club/{club.Slug}").ToString();
|
|
|
|
protected override async Task OnParametersSetAsync()
|
|
{
|
|
loaded = false;
|
|
club = string.IsNullOrWhiteSpace(Slug)
|
|
? null
|
|
: await SessionStore.GetPublicClubBySlugAsync(Slug.Trim());
|
|
loaded = true;
|
|
}
|
|
|
|
private string PublicSessionPath(Guid sessionId) => $"/s/{sessionId}";
|
|
|
|
private static string FormatSeats(WebPublicSession session)
|
|
{
|
|
var seats = session.MaxPlayers.HasValue
|
|
? $"{session.ActivePlayerCount}/{session.MaxPlayers.Value}"
|
|
: $"{session.ActivePlayerCount} игроков";
|
|
|
|
return session.WaitlistedPlayerCount > 0
|
|
? $"{seats}, ожидание {session.WaitlistedPlayerCount}"
|
|
: seats;
|
|
}
|
|
|
|
private static string GetStatusClass(string status) => status switch
|
|
{
|
|
SessionStatus.Confirmed => "status-success",
|
|
SessionStatus.ConfirmationSent => "status-warning",
|
|
SessionStatus.Planned => "status-info",
|
|
_ => "status-neutral"
|
|
};
|
|
|
|
private static string TranslateStatus(string status) => status switch
|
|
{
|
|
SessionStatus.Planned => "Запланировано",
|
|
SessionStatus.ConfirmationSent => "Ждем подтверждения",
|
|
SessionStatus.Confirmed => "Подтверждено",
|
|
_ => status
|
|
};
|
|
}
|