Massive fixes

This commit is contained in:
degradin 2025-03-16 12:47:27 +03:00
parent 0e304a8b2e
commit 33248392ff
3 changed files with 110 additions and 65 deletions

View File

@ -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: () => <Spinner />,
ssr: false
});
const Shop = dynamic(() => import('./Shop'), {
loading: () => <Spinner />,
ssr: false
});
const TransferBalance = dynamic(() => import('./TransferBalance'), {
loading: () => <Spinner />,
ssr: false
});
type SafeUser = Omit<IUser, keyof Document>;
export default function MainApp() {

View File

@ -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<Pick<WebApp,
| 'initData'
| 'initDataUnsafe'
| 'platform'
| 'colorScheme'
| 'themeParams'
| 'isExpanded'
| 'viewportHeight'
| 'viewportStableHeight'
| 'headerColor'
| 'backgroundColor'
| 'isClosingConfirmationEnabled'
| 'BackButton'
| 'MainButton'
| 'ready'
| 'expand'
| 'close'
>>;
export function useTelegramWebApp() {
const [webApp, setWebApp] = useState<WebApp | null>(null);
const [webApp, setWebApp] = useState<SafeWebApp | null>(null);
const [error, setError] = useState<string | null>(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 };

View File

@ -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<WebApp,
| 'initData'
| 'initDataUnsafe'
| 'platform'
| 'colorScheme'
| 'themeParams'
| 'isExpanded'
| 'viewportHeight'
| 'viewportStableHeight'
| 'headerColor'
| 'backgroundColor'
| 'isClosingConfirmationEnabled'
| 'BackButton'
| 'MainButton'
| 'ready'
| 'expand'
| 'close'
>;
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(),
});