feat(rendering): display description, system, duration, format, type and location in Telegram game card

This commit is contained in:
2026-06-13 10:55:03 +03:00
parent 7d5dd2ed0a
commit 3c967dc3e3
12 changed files with 298 additions and 40 deletions
@@ -70,7 +70,17 @@ public sealed class CancelSessionHandler(
// 3. Загружаем весь батч для перерисовки
var batchSessions = await connection.QueryAsync<SessionBatchDto>(
@"SELECT id as SessionId, scheduled_at as ScheduledAt, status as Status, max_players as MaxPlayers, join_link as JoinLink, format as Format, location_address as LocationAddress
@"SELECT id as SessionId,
scheduled_at as ScheduledAt,
status as Status,
max_players as MaxPlayers,
join_link as JoinLink,
format as Format,
location_address as LocationAddress,
description as Description,
system as System,
duration_minutes as DurationMinutes,
is_one_shot as IsOneShot
FROM sessions
WHERE batch_id = @BatchId
ORDER BY scheduled_at",
@@ -141,7 +141,11 @@ public sealed class PromoteWaitlistedPlayerHandler(
max_players AS MaxPlayers,
join_link AS JoinLink,
format AS Format,
location_address AS LocationAddress
location_address AS LocationAddress,
description AS Description,
system AS System,
duration_minutes AS DurationMinutes,
is_one_shot AS IsOneShot
FROM sessions
WHERE batch_id = @BatchId
ORDER BY scheduled_at
@@ -162,7 +162,7 @@ public sealed class RescheduleVotingDeadlineService(
await using var connection = await dataSource.OpenConnectionAsync(ct);
var batchSessions = (await connection.QueryAsync<SessionBatchDto>(
"SELECT id AS SessionId, scheduled_at AS ScheduledAt, status AS Status, max_players AS MaxPlayers, join_link AS JoinLink, format AS Format, location_address AS LocationAddress FROM sessions WHERE batch_id = @BatchId ORDER BY scheduled_at",
"SELECT id AS SessionId, scheduled_at AS ScheduledAt, status AS Status, max_players AS MaxPlayers, join_link AS JoinLink, format AS Format, location_address AS LocationAddress, description AS Description, system AS System, duration_minutes AS DurationMinutes, is_one_shot AS IsOneShot FROM sessions WHERE batch_id = @BatchId ORDER BY scheduled_at",
new { result.BatchId })).ToList();
var batchParticipants = (await connection.QueryAsync<ParticipantBatchDto>(
@@ -17,22 +17,49 @@ public static class TelegramSessionBatchRenderer
foreach (var session in view.Sessions)
{
messageText += $"📅 <b>{session.ScheduledAt.FormatMoscow()}</b>\n";
messageText += session.MaxPlayers.HasValue
? $"👥 Места: {session.ActivePlayerCount}/{session.MaxPlayers.Value}\n"
: $"👥 Игроки ({session.ActivePlayerCount}):\n";
if (!string.IsNullOrEmpty(session.JoinLink))
var tags = new List<string>();
if (!string.IsNullOrWhiteSpace(session.System))
tags.Add($"<b>Система:</b> {System.Net.WebUtility.HtmlEncode(session.System)}");
if (!string.IsNullOrWhiteSpace(session.Format))
tags.Add($"<b>Формат:</b> {System.Net.WebUtility.HtmlEncode(session.Format)}");
tags.Add($"<b>Тип:</b> {(session.IsOneShot ? "One-shot" : "Кампания")}");
if (tags.Count > 0)
{
messageText += "🏷 " + string.Join(" · ", tags) + "\n";
}
if (session.DurationMinutes.HasValue)
{
messageText += $"⏱ <b>Длительность:</b> {FormatDuration(session.DurationMinutes.Value)}\n";
}
if (!string.IsNullOrWhiteSpace(session.Description))
{
messageText += $"📝 <b>Описание:</b>\n{System.Net.WebUtility.HtmlEncode(session.Description)}\n\n";
}
var format = session.Format ?? string.Empty;
var isOnline = string.Equals(format, "Online", StringComparison.OrdinalIgnoreCase);
var isOffline = string.Equals(format, "Offline", StringComparison.OrdinalIgnoreCase);
var isHybrid = string.Equals(format, "Hybrid", StringComparison.OrdinalIgnoreCase);
if ((isOnline || isHybrid) && !string.IsNullOrWhiteSpace(session.JoinLink))
{
var encodedLink = System.Net.WebUtility.HtmlEncode(session.JoinLink);
messageText += $"🔗 Ссылка на игру: <a href=\"{encodedLink}\">{encodedLink}</a>\n";
messageText += $"🔗 <b>Ссылка:</b> <a href=\"{encodedLink}\">{encodedLink}</a>\n";
}
if (string.Equals(session.Format, "Offline", StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrWhiteSpace(session.LocationAddress))
if ((isOffline || isHybrid) && !string.IsNullOrWhiteSpace(session.LocationAddress))
{
messageText += $"📍 Адрес: {System.Net.WebUtility.HtmlEncode(session.LocationAddress)}\n";
messageText += $"📍 <b>Адрес:</b> {System.Net.WebUtility.HtmlEncode(session.LocationAddress)}\n";
}
messageText += session.MaxPlayers.HasValue
? $"👥 <b>Места:</b> {session.ActivePlayerCount}/{session.MaxPlayers.Value}\n"
: $"👥 <b>Игроки ({session.ActivePlayerCount}):</b>\n";
if (session.ActivePlayers.Count > 0)
{
messageText += string.Join("\n", session.ActivePlayers.Select(p =>
@@ -45,7 +72,7 @@ public static class TelegramSessionBatchRenderer
if (session.WaitlistedPlayers.Count > 0)
{
messageText += $"⏳ Лист ожидания ({session.WaitlistedPlayers.Count}):\n";
messageText += $"⏳ <b>Лист ожидания ({session.WaitlistedPlayers.Count}):</b>\n";
messageText += string.Join("\n", session.WaitlistedPlayers.Select(p =>
$" ⏱ {(p.TelegramUsername != null ? "@" + p.TelegramUsername : p.DisplayName)}")) + "\n";
}
@@ -67,4 +94,14 @@ public static class TelegramSessionBatchRenderer
return (messageText, new InlineKeyboardMarkup(buttons));
}
private static string FormatDuration(int minutes)
{
if (minutes <= 0) return "0 мин";
var hours = minutes / 60;
var mins = minutes % 60;
if (hours > 0 && mins > 0) return $"{hours} ч {mins} мин";
if (hours > 0) return $"{hours} ч";
return $"{mins} мин";
}
}