import { useEffect, useCallback, useMemo, useRef } from 'react'; import { Link, useNavigate, useSearchParams } from 'react-router'; import { useTranslation } from 'react-i18next'; import { useQuery } from '@tanstack/react-query'; import { openLink as sdkOpenLink } from '@telegram-apps/sdk-react'; import { subscriptionApi } from '../api/subscription'; import { useTelegramSDK } from '../hooks/useTelegramSDK'; import { useHaptic } from '@/platform'; import { resolveTemplate, hasTemplates } from '../utils/templateEngine'; import { isHappCryptolinkMode, resolveConnectionUrlForUi } from '../utils/connectionLink'; import { useAuthStore } from '../store/auth'; import type { AppConfig, RemnawavePlatformData } from '../types'; import InstallationGuide from '../components/connection/InstallationGuide'; export default function Connection() { const { t, i18n } = useTranslation(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const subId = searchParams.get('sub') ? Number(searchParams.get('sub')) : undefined; const user = useAuthStore((state) => state.user); const isAdmin = useAuthStore((state) => state.isAdmin); const { isTelegramWebApp } = useTelegramSDK(); const { impact: hapticImpact } = useHaptic(); const hapticRef = useRef(hapticImpact); hapticRef.current = hapticImpact; const { data: appConfig, isLoading, error, } = useQuery({ queryKey: ['appConfig', subId], queryFn: () => subscriptionApi.getAppConfig(subId), }); const { data: connectionLink, isLoading: isConnectionLinkLoading } = useQuery({ queryKey: ['connectionLink', subId], queryFn: () => subscriptionApi.getConnectionLink(subId), retry: false, staleTime: 0, }); const qrConnectionUrl = useMemo( () => resolveConnectionUrlForUi({ mode: connectionLink?.connect_mode, happSchemeLink: connectionLink?.happ_scheme_link, displayLink: connectionLink?.display_link, subscriptionUrl: connectionLink?.subscription_url, happCryptLink: connectionLink?.happ_cryptolink, happCryptoLink: connectionLink?.happ_crypto_link, happLink: connectionLink?.happ_link, fallbackUrl: appConfig?.subscriptionUrl, }), [ appConfig?.subscriptionUrl, connectionLink?.connect_mode, connectionLink?.display_link, connectionLink?.happ_cryptolink, connectionLink?.happ_crypto_link, connectionLink?.happ_link, connectionLink?.happ_scheme_link, connectionLink?.subscription_url, ], ); const handleGoBack = useCallback(() => { navigate(-1); }, [navigate]); const handleOpenQR = useCallback(() => { if (!qrConnectionUrl) return; navigate('/connection/qr', { replace: !isTelegramWebApp, state: { url: qrConnectionUrl, hideLink: connectionLink?.hide_link ?? appConfig?.hideLink ?? false, subscriptionId: subId, }, }); }, [ navigate, qrConnectionUrl, connectionLink?.hide_link, appConfig?.hideLink, isTelegramWebApp, subId, ]); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') { e.preventDefault(); handleGoBack(); } }; document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); }, [handleGoBack]); const resolveUrl = useCallback( (url: string): string => { if (!hasTemplates(url) || !appConfig?.subscriptionUrl) return url; return resolveTemplate(url, { subscriptionUrl: appConfig.subscriptionUrl, username: user?.username ?? undefined, }); }, [appConfig?.subscriptionUrl, user?.username], ); const openDeepLink = useCallback( (deepLink: string) => { let resolved = deepLink; if (isHappCryptolinkMode(connectionLink?.connect_mode) && qrConnectionUrl) { // In HAPP cryptolink mode always open the resolved happ://crypt... URL. resolved = qrConnectionUrl; } else if (hasTemplates(resolved)) { resolved = resolveUrl(resolved); } const isHttpUrl = /^https?:\/\//i.test(resolved); const finalUrlForTelegram = isHttpUrl ? resolved : `${window.location.origin}/miniapp/redirect.html?url=${encodeURIComponent(resolved)}&lang=${i18n.language || 'en'}`; if (isTelegramWebApp) { try { sdkOpenLink(finalUrlForTelegram, { tryInstantView: false }); return; } catch { // SDK not available, fallback } } // In regular browsers open deeplink directly (without intermediate redirect page). window.location.href = resolved; }, [isTelegramWebApp, i18n.language, resolveUrl, connectionLink?.connect_mode, qrConnectionUrl], ); // Check if any platform has configured apps const hasApps = useMemo(() => { if (!appConfig?.platforms) return false; return Object.values(appConfig.platforms).some( (p: RemnawavePlatformData) => p.apps && p.apps.length > 0, ); }, [appConfig?.platforms]); if (isLoading || isConnectionLinkLoading) { return (
); } if (error || !appConfig || !hasApps) { return (

{t('subscription.connection.notConfigured')}

{isAdmin ? t('subscription.connection.notConfiguredAdmin') : t('subscription.connection.notConfiguredUser')}

{isAdmin && ( {t('subscription.connection.goToApps')} )}
); } // No subscription if (!appConfig.hasSubscription) { return (

{t('subscription.connection.title')}

{t('subscription.connection.noSubscription')}

); } return ( ); }