From 33248392ffdfa41df2543ea099d6e339dd447e35 Mon Sep 17 00:00:00 2001 From: degradin Date: Sun, 16 Mar 2025 12:47:27 +0300 Subject: [PATCH] Massive fixes --- app/components/MainApp.tsx | 20 ++++++-- app/hooks/useTelegramWebApp.ts | 83 +++++++++++++++++----------------- app/utils/demo.ts | 72 +++++++++++++++++++++-------- 3 files changed, 110 insertions(+), 65 deletions(-) diff --git a/app/components/MainApp.tsx b/app/components/MainApp.tsx index 970bf01..f6b5adb 100644 --- a/app/components/MainApp.tsx +++ b/app/components/MainApp.tsx @@ -1,15 +1,29 @@ 'use client'; +import dynamic from 'next/dynamic'; import React, { useState, useEffect } from 'react'; import { Box, VStack, Spinner, Center, useToast } from '@chakra-ui/react'; -import UserProfile from './UserProfile'; -import Shop from './Shop'; -import TransferBalance from './TransferBalance'; import { auth, getProfile, getShopItems, purchaseItem, transferBalance } from '../utils/api'; import { IUser } from '../../backend/models/User'; import { IShopItem } from '../../backend/models/ShopItem'; import { useTelegramWebApp } from '../hooks/useTelegramWebApp'; +// Динамический импорт компонентов для клиентской стороны +const UserProfile = dynamic(() => import('./UserProfile'), { + loading: () => , + ssr: false +}); + +const Shop = dynamic(() => import('./Shop'), { + loading: () => , + ssr: false +}); + +const TransferBalance = dynamic(() => import('./TransferBalance'), { + loading: () => , + ssr: false +}); + type SafeUser = Omit; export default function MainApp() { diff --git a/app/hooks/useTelegramWebApp.ts b/app/hooks/useTelegramWebApp.ts index b237ecc..834ec45 100644 --- a/app/hooks/useTelegramWebApp.ts +++ b/app/hooks/useTelegramWebApp.ts @@ -2,73 +2,72 @@ import { useEffect, useState } from 'react'; import { isDemoMode, getDemoWebApp } from '../utils/demo'; +import type { WebApp } from '@twa-dev/types'; -export type WebApp = { - initData: string; - initDataUnsafe: { - query_id: string; - user: { - id: string; - first_name: string; - username?: string; - language_code: string; - }; - auth_date: number; - hash: string; - }; - platform: string; - colorScheme: string; - themeParams: { - bg_color: string; - text_color: string; - hint_color: string; - link_color: string; - button_color: string; - button_text_color: string; - }; - isExpanded: boolean; - viewportHeight: number; - viewportStableHeight: number; - headerColor: string; - backgroundColor: string; - ready: () => void; - expand: () => void; - close: () => void; -}; +type SafeWebApp = Partial>; export function useTelegramWebApp() { - const [webApp, setWebApp] = useState(null); + const [webApp, setWebApp] = useState(null); const [error, setError] = useState(null); const [isInitialized, setIsInitialized] = useState(false); useEffect(() => { + let isMounted = true; + const initWebApp = async () => { try { if (isDemoMode()) { - const demoWebApp = getDemoWebApp(); - setWebApp(demoWebApp); - setIsInitialized(true); + if (isMounted) { + const demoWebApp = getDemoWebApp(); + setWebApp(demoWebApp); + setIsInitialized(true); + } return; } if (typeof window !== 'undefined') { const WebAppModule = await import('@twa-dev/sdk'); - if (WebAppModule.default) { - setWebApp(WebAppModule.default); - setIsInitialized(true); - } else { - throw new Error('WebApp не найден'); + if (isMounted) { + if (WebAppModule.default) { + setWebApp(WebAppModule.default as SafeWebApp); + setIsInitialized(true); + } else { + throw new Error('WebApp не найден'); + } } } } catch (err) { console.error('WebApp initialization error:', err); - setError('Ошибка инициализации Telegram Web App'); + if (isMounted) { + setError('Ошибка инициализации Telegram Web App'); + } } }; if (!isInitialized) { initWebApp(); } + + return () => { + isMounted = false; + }; }, [isInitialized]); return { webApp, error, isInitialized }; diff --git a/app/utils/demo.ts b/app/utils/demo.ts index 65951bf..e438c64 100644 --- a/app/utils/demo.ts +++ b/app/utils/demo.ts @@ -1,28 +1,54 @@ 'use client'; +import type { WebApp, WebAppUser, WebAppInitData, Platforms } from '@twa-dev/types'; + // Демо данные для тестирования без Telegram -const demoUser = { - id: 'demo_user_123', +const demoUser: WebAppUser = { + id: 12345, first_name: 'Demo', username: 'demo_user', - language_code: 'ru' + language_code: 'ru', + is_premium: false }; -const demoInitData = { +const demoInitData: WebAppInitData = { query_id: 'demo_query', user: demoUser, auth_date: Date.now(), - hash: 'demo_hash' + hash: 'demo_hash', + start_param: '' }; export const isDemoMode = () => { return typeof window !== 'undefined' && new URLSearchParams(window.location.search).has('demo'); }; -export const getDemoWebApp = () => ({ +// Создаем заглушки для методов WebApp +const createNoopFunction = () => () => {}; + +type SafeWebApp = Pick; + +export const getDemoWebApp = (): SafeWebApp => ({ initData: 'demo_mode', initDataUnsafe: demoInitData, - platform: 'demo', + platform: 'WEBVIEW' as Platforms, colorScheme: 'light', themeParams: { bg_color: '#ffffff', @@ -30,7 +56,8 @@ export const getDemoWebApp = () => ({ hint_color: '#999999', link_color: '#2481cc', button_color: '#2481cc', - button_text_color: '#ffffff' + button_text_color: '#ffffff', + secondary_bg_color: '#f0f0f0' }, isExpanded: true, viewportHeight: typeof window !== 'undefined' ? window.innerHeight : 800, @@ -40,7 +67,10 @@ export const getDemoWebApp = () => ({ isClosingConfirmationEnabled: true, BackButton: { isVisible: false, - onClick: () => {}, + onClick: createNoopFunction(), + offClick: createNoopFunction(), + show: createNoopFunction(), + hide: createNoopFunction() }, MainButton: { text: '', @@ -49,16 +79,18 @@ export const getDemoWebApp = () => ({ isVisible: false, isProgressVisible: false, isActive: true, - setText: () => {}, - onClick: () => {}, - show: () => {}, - hide: () => {}, - enable: () => {}, - disable: () => {}, - showProgress: () => {}, - hideProgress: () => {}, + setText: createNoopFunction(), + onClick: createNoopFunction(), + offClick: createNoopFunction(), + show: createNoopFunction(), + hide: createNoopFunction(), + enable: createNoopFunction(), + disable: createNoopFunction(), + showProgress: createNoopFunction(), + hideProgress: createNoopFunction(), + setParams: createNoopFunction() }, - ready: () => {}, - expand: () => {}, - close: () => {}, + ready: createNoopFunction(), + expand: createNoopFunction(), + close: createNoopFunction(), }); \ No newline at end of file