Add files via upload

This commit is contained in:
Egor
2026-01-15 19:18:17 +03:00
committed by GitHub
parent b118008cdc
commit 7be6b5c0ae
70 changed files with 21835 additions and 0 deletions

View File

@@ -0,0 +1,173 @@
import { useEffect, useState } from 'react'
import { useNavigate, useSearchParams } from 'react-router-dom'
import { useTranslation } from 'react-i18next'
import { useQuery } from '@tanstack/react-query'
import { useAuthStore } from '../store/auth'
import { brandingApi } from '../api/branding'
export default function TelegramRedirect() {
const { t } = useTranslation()
const navigate = useNavigate()
const [searchParams] = useSearchParams()
const { loginWithTelegram, isAuthenticated, isLoading: authLoading } = useAuthStore()
const [status, setStatus] = useState<'loading' | 'success' | 'error' | 'not-telegram'>('loading')
const [errorMessage, setErrorMessage] = useState('')
// Get branding for nice display
const { data: branding } = useQuery({
queryKey: ['branding'],
queryFn: brandingApi.getBranding,
staleTime: 60000,
})
const appName = branding ? branding.name : (import.meta.env.VITE_APP_NAME || 'VPN')
const logoLetter = branding?.logo_letter || import.meta.env.VITE_APP_LOGO || 'V'
const logoUrl = branding ? brandingApi.getLogoUrl(branding) : null
// Get redirect target from URL params
const redirectTo = searchParams.get('redirect') || '/'
useEffect(() => {
// If already authenticated, redirect immediately
if (isAuthenticated && !authLoading) {
setStatus('success')
setTimeout(() => navigate(redirectTo), 500)
return
}
const initTelegram = async () => {
// Check if running in Telegram WebApp
const tg = window.Telegram?.WebApp
if (!tg?.initData) {
// Not in Telegram, show message and redirect to login
setStatus('not-telegram')
setTimeout(() => navigate('/login'), 2000)
return
}
// Initialize Telegram WebApp
tg.ready()
tg.expand()
// Set theme colors if available
if (tg.themeParams) {
document.documentElement.style.setProperty('--tg-theme-bg-color', tg.themeParams.bg_color || '#1a1a2e')
document.documentElement.style.setProperty('--tg-theme-text-color', tg.themeParams.text_color || '#ffffff')
}
try {
await loginWithTelegram(tg.initData)
setStatus('success')
// Small delay for nice UX
setTimeout(() => {
navigate(redirectTo)
}, 800)
} catch (err: unknown) {
console.error('Telegram auth failed:', err)
const error = err as { response?: { data?: { detail?: string } } }
setErrorMessage(error.response?.data?.detail || t('auth.telegramRequired'))
setStatus('error')
}
}
// Small delay to show loading screen
setTimeout(initTelegram, 300)
}, [loginWithTelegram, navigate, isAuthenticated, authLoading, redirectTo, t])
// Handle retry
const handleRetry = () => {
setStatus('loading')
setErrorMessage('')
window.location.reload()
}
return (
<div className="min-h-screen flex items-center justify-center p-4">
{/* Background */}
<div className="fixed inset-0 bg-gradient-to-br from-dark-950 via-dark-900 to-dark-950" />
<div className="fixed inset-0 bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-accent-500/10 via-transparent to-transparent" />
<div className="relative text-center max-w-sm w-full">
{/* Logo */}
<div className="mx-auto w-20 h-20 rounded-2xl bg-gradient-to-br from-accent-400 to-accent-600 flex items-center justify-center mb-6 shadow-lg shadow-accent-500/30 overflow-hidden">
{branding?.has_custom_logo && logoUrl ? (
<img src={logoUrl} alt={appName} className="w-full h-full object-cover" />
) : (
<span className="text-white font-bold text-3xl">{logoLetter}</span>
)}
</div>
<h1 className="text-2xl font-bold text-dark-50 mb-2">{appName}</h1>
{/* Loading State */}
{status === 'loading' && (
<div className="mt-8">
<div className="w-10 h-10 border-3 border-accent-500 border-t-transparent rounded-full animate-spin mx-auto mb-4" />
<p className="text-dark-400">{t('auth.authenticating')}</p>
<p className="text-sm text-dark-500 mt-2">{t('common.loading')}</p>
</div>
)}
{/* Success State */}
{status === 'success' && (
<div className="mt-8">
<div className="w-16 h-16 rounded-full bg-success-500/20 flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-success-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M4.5 12.75l6 6 9-13.5" />
</svg>
</div>
<p className="text-dark-200">{t('auth.loginSuccess')}</p>
<p className="text-sm text-dark-500 mt-2">Перенаправление...</p>
</div>
)}
{/* Error State */}
{status === 'error' && (
<div className="mt-8">
<div className="w-16 h-16 rounded-full bg-error-500/20 flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-error-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</div>
<p className="text-dark-200 mb-2">{t('auth.loginFailed')}</p>
<p className="text-sm text-error-400 mb-6">{errorMessage}</p>
<div className="flex flex-col gap-3">
<button onClick={handleRetry} className="btn-primary w-full">
{t('auth.tryAgain')}
</button>
<button onClick={() => navigate('/login')} className="btn-secondary w-full">
Войти другим способом
</button>
</div>
</div>
)}
{/* Not in Telegram State */}
{status === 'not-telegram' && (
<div className="mt-8">
<div className="w-16 h-16 rounded-full bg-warning-500/20 flex items-center justify-center mx-auto mb-4">
<svg className="w-8 h-8 text-warning-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z" />
</svg>
</div>
<p className="text-dark-200 mb-2">Откройте в Telegram</p>
<p className="text-sm text-dark-400 mb-6">
Для автоматического входа откройте это приложение через бота в Telegram
</p>
<p className="text-sm text-dark-500">Перенаправление на страницу входа...</p>
</div>
)}
{/* Telegram branding */}
<div className="mt-12 flex items-center justify-center gap-2 text-dark-600">
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="currentColor">
<path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/>
</svg>
<span className="text-xs">Telegram Mini App</span>
</div>
</div>
</div>
)
}