From e06bdc308f0ac049cc715bf1497e3f8320cab259 Mon Sep 17 00:00:00 2001 From: Umbrix Dev Date: Wed, 4 Feb 2026 05:18:18 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=8F=A0=20Page:=20=D0=93=D0=BB=D0=B0=D0=B2?= =?UTF-8?q?=D0=BD=D0=B0=D1=8F=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86?= =?UTF-8?q?=D0=B0=20-=20=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=B4=D0=BF=D0=B8=D1=81=D0=BA=D0=B8=20=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=B5=D0=B9=D1=81=D1=82=D0=B2=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/page.tsx | 592 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 592 insertions(+) create mode 100644 app/page.tsx diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..507b467 --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,592 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { useRouter } from 'next/navigation'; +import Link from 'next/link'; +import QRCodeModal from '@/components/QRCodeModal'; +import ReferralModal from '@/components/ReferralModal'; +import { marzbanApi } from '@/lib/marzban-api'; +import { getSubscriptionUrl, MARZBAN_SUBSCRIPTION_URL } from '@/lib/constants'; +import { + Shield, + Settings, + Gift, + DollarSign, + Wrench, + User, + HelpCircle, + ExternalLink, + X, + Key, + CreditCard, + Lock, + Eye, + Ban, + MessageCircle, + UserPlus, + QrCode, + Copy, + ChevronRight, + Share2, +} from 'lucide-react'; + +export default function Home() { + const router = useRouter(); + const [hasSubscription, setHasSubscription] = useState(false); + const [isMenuOpen, setIsMenuOpen] = useState(false); + const [isKeyMenuOpen, setIsKeyMenuOpen] = useState(false); + const [isQROpen, setIsQROpen] = useState(false); + const [isReferralOpen, setIsReferralOpen] = useState(false); + const [subscriptionStatus, setSubscriptionStatus] = useState<'active' | 'expired' | 'none'>('none'); + const [expiryDate, setExpiryDate] = useState(''); + const [showToast, setShowToast] = useState(false); + const [toastMessage, setToastMessage] = useState(''); + const [subscriptionToken, setSubscriptionToken] = useState(null); + const [isLoading, setIsLoading] = useState(true); + + const subscriptionUrl = subscriptionToken ? getSubscriptionUrl(subscriptionToken) : MARZBAN_SUBSCRIPTION_URL; + + const showToastNotification = (message: string) => { + setToastMessage(message); + setShowToast(true); + setTimeout(() => setShowToast(false), 3000); + }; + + // Загружаем подписку при монтировании - ЧЕРЕЗ API, НЕ localStorage! + useEffect(() => { + const loadSubscription = async () => { + // Получаем Telegram данные + const telegramWebApp = (window as any).Telegram?.WebApp; + const telegramId = telegramWebApp?.initDataUnsafe?.user?.id; + const telegramUsername = telegramWebApp?.initDataUnsafe?.user?.username; + + console.log('🔍 Loading subscription for:', { telegramId, telegramUsername }); + + if (!telegramId && !telegramUsername) { + console.log('⚠️ No Telegram data - probably opened in browser'); + setIsLoading(false); + return; + } + + try { + // Запрашиваем подписку по Telegram ID через API + const params = new URLSearchParams(); + if (telegramId) params.append('telegramId', telegramId.toString()); + if (telegramUsername) params.append('telegramUsername', telegramUsername); + + const response = await fetch(`/api/user-subscription?${params.toString()}`); + const data = await response.json(); + + console.log('📥 API response:', data); + + if (data.success && data.hasSubscription) { + setSubscriptionToken(data.token); + setHasSubscription(true); + const status = data.status === 'active' ? 'active' : 'expired'; + setSubscriptionStatus(status); + if (data.expire) { + setExpiryDate(marzbanApi.formatExpireDate(data.expire)); + } + } else { + console.log('❌ No subscription found'); + } + } catch (error) { + console.error('Failed to load subscription:', error); + } + + setIsLoading(false); + }; + + loadSubscription(); + }, []); // Загружаем при каждом монтировании компонента + // ОТКЛЮЧАЕМ автоматическую проверку API при загрузке (чтобы не зависала страница) + // API проверка будет только на странице /subscription/[token] + // useEffect(() => { + // async function checkSubscription() { + // try { + // const userData = await marzbanApi.getUserInfo(subscriptionToken); + // + // if (userData.status === 'active') { + // setHasSubscription(true); + // setSubscriptionStatus('active'); + // setExpiryDate(marzbanApi.formatExpireDate(userData.expire)); + // } else if (userData.status === 'expired') { + // setHasSubscription(false); + // setSubscriptionStatus('expired'); + // setExpiryDate(marzbanApi.formatExpireDate(userData.expire)); + // } else { + // setHasSubscription(false); + // setSubscriptionStatus('none'); + // } + // } catch (error) { + // console.error('Failed to check subscription:', error); + // setHasSubscription(false); + // setSubscriptionStatus('none'); + // } + // } + // + // checkSubscription(); + // }, []); + + const copyToClipboard = async (text: string) => { + try { + await navigator.clipboard.writeText(text); + showToastNotification('✅ Скопировано в буфер обмена!'); + } catch (err) { + console.error('Failed to copy:', err); + showToastNotification('❌ Ошибка копирования'); + } + }; + const shareReferralLink = async () => { + // Генерируем реферальную ссылку (TODO: заменить на реальный user ID после авторизации) + const userId = subscriptionToken?.split('_')[0] || 'DEMO'; + const referralUrl = `https://t.me/umbrix_bot?start=ref_${userId}`; + const shareText = `🚀 Попробуй Umbrix VPN - быстрый и безопасный VPN!\n\n✨ Получи 7 дней бесплатно по моей ссылке:\n${referralUrl}`; + + // Проверяем поддержку Web Share API + if (navigator.share) { + try { + await navigator.share({ + title: 'Umbrix VPN - Пригласи друга!', + text: shareText, + url: referralUrl, + }); + } catch (err) { + // Пользователь отменил или ошибка + if ((err as Error).name !== 'AbortError') { + console.error('Share failed:', err); + // Fallback: копируем в буфер + copyToClipboard(shareText); + } + } + } else { + // Fallback для браузеров без поддержки Share API + copyToClipboard(shareText); + } + }; + return ( +
+ {/* Header */} +
+
+ + + Umbrix + +
+ +
+ + {/* Бегущая строка с преимуществами */} +
+
+
+ + Без логов +
+
+ + Без регистрации +
+
+ + Не отслеживаем +
+
+ + Не продаём ваш трафик +
+ {/* Дублируем для бесшовной анимации */} +
+ + Без логов +
+
+ + Без регистрации +
+
+ + Не отслеживаем +
+
+ + Не продаём ваш трафик +
+
+
+ + {/* Main Content */} +
+ {/* Hero Section - Логотип и статус */} +
+
🛡️
+

Umbrix VPN

+

Быстрый и безопасный VPN

+
+ + {/* Status */} +
+ {hasSubscription ? ( + + Моя подписка ✅ Активна до {expiryDate || '...'} + + ) : subscriptionStatus === 'expired' ? ( +
+ ⚠️ Подписка истекла {expiryDate} +
+ ) : ( +
+ ⚠️ Нет подписки +
+ )} +
+ + {/* Action Buttons */} +
+ {/* Показываем trial только если нет активной подписки */} + {!hasSubscription && ( + } + text="Попробовать 7 дней бесплатно" + onClick={() => (window.location.href = '/plans')} + /> + )} + } + text="Купить подписку от 99₽" + onClick={() => (window.location.href = '/plans')} + /> + + } + text="Настроить VPN" + onClick={() => {}} + /> + +
+
+ + {/* Bottom Navigation */} + + + {/* Account Menu Modal */} + {isMenuOpen && ( +
setIsMenuOpen(false)} + > +
e.stopPropagation()} + > + {/* Header */} +
+

+ Меню аккаунта +

+ +
+ + {/* Menu Items */} +
+ {hasSubscription ? ( + <> + + } + label="📊 Моя подписка" + onClick={() => setIsMenuOpen(false)} + /> + + + } + label="🔑 Ключ подписки" + onClick={() => { + setIsMenuOpen(false); + setIsKeyMenuOpen(true); + }} + /> + + ) : ( + + } + label="🛒 Купить подписку" + onClick={() => setIsMenuOpen(false)} + /> + + )} + + + } + label="💳 Тарифы" + onClick={() => setIsMenuOpen(false)} + /> + + + + } + label="⚙️ Настройки" + onClick={() => setIsMenuOpen(false)} + /> + + + } + label="💬 Поддержка" + onClick={() => { + setIsMenuOpen(false); + router.push('/help'); + }} + /> + + } + label="🎁 Пригласить друга" + onClick={() => { + setIsMenuOpen(false); + setIsReferralOpen(true); + }} + /> +
+
+
+ )} + + {/* Key Subscription Menu Modal */} + {isKeyMenuOpen && ( +
setIsKeyMenuOpen(false)} + > +
e.stopPropagation()} + > + {/* Header */} +
+

+ Ключ подписки +

+ +
+ + {/* Menu Items */} +
+ } + label="Скопировать ссылку" + onClick={() => { + copyToClipboard(subscriptionUrl); + setIsKeyMenuOpen(false); + }} + /> + + } + label="Показать QR код" + onClick={() => { + setIsKeyMenuOpen(false); + setIsQROpen(true); + }} + /> + + } + label="Поделиться подпиской" + onClick={() => { + // TODO: Проверка тарифа, затем share sheet + if (navigator.share) { + navigator.share({ + title: 'VPN подписка', + text: 'Моя VPN подписка', + url: subscriptionUrl, + }); + } else { + copyToClipboard(subscriptionUrl); + } + setIsKeyMenuOpen(false); + }} + /> +
+
+
+ )} + + {/* QR Code Modal */} + setIsQROpen(false)} + url={subscriptionUrl} + title="QR код подписки" + /> + + {/* Referral Modal */} + setIsReferralOpen(false)} + referralUrl={`https://t.me/umbrix_bot?start=ref_${subscriptionToken?.split('_')[0] || 'DEMO'}`} + onShare={() => { + shareReferralLink(); + setIsReferralOpen(false); + }} + onCopy={() => { + const userId = subscriptionToken?.split('_')[0] || 'DEMO'; + const referralUrl = `https://t.me/umbrix_bot?start=ref_${userId}`; + copyToClipboard(referralUrl); + setIsReferralOpen(false); + }} + /> + + {/* Toast Notification */} + {showToast && ( +
+
+ {toastMessage} +
+
+ )} +
+ ); +} + +function ActionButton({ + icon, + text, + onClick, +}: { + icon: React.ReactNode; + text: string; + onClick: () => void; +}) { + return ( + + ); +} + +function NavButton({ + icon, + label, + href, + onClick, +}: { + icon: React.ReactNode; + label: string; + href?: string; + onClick?: () => void; +}) { + if (onClick) { + return ( + + ); + } + + return ( + +
+ {icon} + {label} +
+ + ); +} + +function MenuButton({ + icon, + label, + onClick, +}: { + icon: React.ReactNode; + label: string; + onClick: () => void; +}) { + return ( + + ); +} +