feat: add telegram mini app dashboard
Deploy Telegram Bot / build-and-push (push) Successful in 23s
Deploy Telegram Bot / deploy (push) Successful in 10s

This commit is contained in:
2026-04-28 14:56:55 +03:00
parent 5082dd4fcf
commit 41f2ea6e90
21 changed files with 698 additions and 26 deletions
+35
View File
@@ -13,6 +13,7 @@
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="@Assets["app.css"]" />
<link rel="stylesheet" href="@Assets["GmRelay.Web.styles.css"]" />
<script src="https://telegram.org/js/telegram-web-app.js"></script>
<ImportMap />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet @rendermode="InteractiveServer" />
@@ -23,6 +24,14 @@
<ReconnectModal />
<script src="@Assets["_framework/blazor.web.js"]"></script>
<script>
(function () {
if (window.Telegram && window.Telegram.WebApp && window.Telegram.WebApp.initData) {
var webApp = window.Telegram.WebApp;
document.body.classList.add('telegram-mini-app');
webApp.ready();
}
})();
window.loadTelegramWidget = function (botUsername, authUrl) {
var container = document.getElementById('telegram-login-container');
if (!container) return;
@@ -36,6 +45,32 @@
script.setAttribute('data-request-access', 'write');
container.appendChild(script);
};
window.authenticateTelegramMiniApp = async function (authUrl, redirectUrl) {
if (!window.Telegram || !window.Telegram.WebApp || !window.Telegram.WebApp.initData) {
return false;
}
var webApp = window.Telegram.WebApp;
document.body.classList.add('telegram-mini-app');
webApp.ready();
webApp.expand();
var response = await fetch(authUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'same-origin',
body: JSON.stringify({ initData: webApp.initData })
});
if (!response.ok) {
return false;
}
var payload = await response.json();
window.location.href = payload.redirectUrl || redirectUrl || '/';
return true;
};
</script>
</body>
@@ -60,12 +60,17 @@
/* === Mobile Responsive === */
@media (max-width: 768px) {
.sidebar {
transform: translateX(-100%);
width: 280px;
transform: none;
width: 100%;
height: auto;
min-height: 0;
position: sticky;
border-right: none;
border-bottom: 1px solid var(--border-color);
}
.sidebar.open {
transform: translateX(0);
.page {
display: block;
}
.main-area {
@@ -56,7 +56,7 @@
</button>
</form>
<div class="nav-version">v1.8.2</div>
<div class="nav-version">v1.9.0</div>
</div>
</Authorized>
<NotAuthorized>
@@ -0,0 +1,70 @@
@page "/miniapp"
@using Microsoft.AspNetCore.Components.Authorization
@inject IJSRuntime JS
@inject NavigationManager Navigation
<PageTitle>Mini App Dashboard — GM-Relay</PageTitle>
<div class="mini-app-page">
<div class="mini-app-auth-card">
<div class="mini-app-logo">🎲</div>
<h1>GM-Relay</h1>
<p>@statusMessage</p>
@if (showFallback)
{
<a href="/login" class="btn-gm btn-gm-primary">Войти через Telegram</a>
}
</div>
</div>
@code {
private string statusMessage = "Открываем dashboard внутри Telegram...";
private bool showFallback;
[CascadingParameter]
private Task<AuthenticationState>? AuthStateTask { get; set; }
protected override async Task OnInitializedAsync()
{
if (AuthStateTask is null)
{
return;
}
var user = (await AuthStateTask).User;
if (user.Identity?.IsAuthenticated == true)
{
Navigation.NavigateTo("/");
}
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (!firstRender)
{
return;
}
try
{
var authenticated = await JS.InvokeAsync<bool>(
"authenticateTelegramMiniApp",
"/auth/telegram-webapp",
"/");
if (!authenticated)
{
statusMessage = "Mini App доступен из Telegram. Для браузера используйте обычный вход.";
showFallback = true;
StateHasChanged();
}
}
catch (JSException)
{
statusMessage = "Не удалось получить данные Telegram Mini App. Попробуйте открыть dashboard из бота.";
showFallback = true;
StateHasChanged();
}
}
}