156 lines
6.6 KiB
TypeScript
156 lines
6.6 KiB
TypeScript
import React, { lazy, Suspense, useEffect } from 'react';
|
||
import { BrowserRouter, Routes, Route, Navigate, Outlet, useNavigate, useLocation } from 'react-router-dom';
|
||
import Layout from './components/layout/Layout';
|
||
import Home from './screens/Home';
|
||
import { initializeUserId } from './constants/user';
|
||
import { trackScreenView } from './services/analyticsService';
|
||
|
||
// Ленивая загрузка компонентов
|
||
const OnboardingWelcome = lazy(() => import('./screens/onboarding/OnboardingWelcome'));
|
||
const OnboardingHowTo = lazy(() => import('./screens/onboarding/OnboardingHowTo'));
|
||
const OnboardingStickerPacks = lazy(() => import('./screens/onboarding/OnboardingStickerPacks'));
|
||
const TermsAndConditions = lazy(() => import('./screens/onboarding/TermsAndConditions'));
|
||
const CreateSticker = lazy(() => import('./screens/CreateSticker'));
|
||
const Gallery = lazy(() => import('./screens/Gallery'));
|
||
const Profile = lazy(() => import('./screens/Profile'));
|
||
const StickerPacks = lazy(() => import('./screens/StickerPacks'));
|
||
const CreateStickerPack = lazy(() => import('./screens/CreateStickerPack'));
|
||
const AddStickerToPackScreen = lazy(() => import('./screens/AddStickerToPackScreen'));
|
||
const History = lazy(() => import('./screens/History'));
|
||
const CropPhoto = lazy(() => import('./screens/CropPhoto'));
|
||
|
||
// Компонент для отображения состояния загрузки
|
||
const LoadingScreen = () => (
|
||
<div style={{
|
||
display: 'flex',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
height: '100vh'
|
||
}}>
|
||
Загрузка...
|
||
</div>
|
||
);
|
||
|
||
// Компонент для проверки онбординга
|
||
const AppContent: React.FC = () => {
|
||
const navigate = useNavigate();
|
||
const location = useLocation();
|
||
|
||
useEffect(() => {
|
||
// Инициализируем ID пользователя при запуске приложения
|
||
initializeUserId();
|
||
|
||
// Стабилизируем окно и отключаем вертикальные свайпы
|
||
if (window.Telegram?.WebApp) {
|
||
// Стабилизация окна (особенно важно для iPhone)
|
||
window.Telegram.WebApp.expand();
|
||
|
||
// Отключаем вертикальные свайпы для предотвращения случайного сворачивания WebApp
|
||
if (window.Telegram.WebApp.isVersionAtLeast('6.9')) {
|
||
window.Telegram.WebApp.disableVerticalSwipes();
|
||
}
|
||
}
|
||
|
||
// Проверяем, видел ли пользователь онбординг и принял ли условия
|
||
const hasSeenOnboarding = localStorage.getItem('hasSeenOnboarding') === 'true';
|
||
const hasAcceptedTerms = localStorage.getItem('hasAcceptedTerms') === 'true';
|
||
|
||
// Если не видел онбординг и не на странице онбординга или условий
|
||
if (!hasSeenOnboarding && !location.pathname.includes('/onboarding')) {
|
||
navigate('/onboarding/welcome');
|
||
}
|
||
// Если видел онбординг, но не принял условия и не на странице условий
|
||
else if (hasSeenOnboarding && !hasAcceptedTerms && !location.pathname.includes('/onboarding/terms')) {
|
||
navigate('/onboarding/terms');
|
||
}
|
||
}, [navigate, location.pathname]);
|
||
|
||
// Отслеживаем изменение маршрута для аналитики
|
||
useEffect(() => {
|
||
// Получаем название экрана из пути
|
||
let screenName = location.pathname;
|
||
if (screenName === '/') {
|
||
screenName = 'Главная';
|
||
} else {
|
||
// Преобразуем путь в более читаемое название
|
||
screenName = screenName
|
||
.replace('/onboarding/welcome', 'Онбординг: Приветствие')
|
||
.replace('/onboarding/how-to', 'Онбординг: Как использовать')
|
||
.replace('/onboarding/sticker-packs', 'Онбординг: Стикер-паки')
|
||
.replace('/onboarding/terms', 'Условия использования')
|
||
.replace('/create', 'Создание стикера')
|
||
.replace('/gallery', 'Галерея')
|
||
.replace('/packs', 'Стикер-паки')
|
||
.replace('/create-sticker-pack', 'Создание стикер-пака')
|
||
.replace('/profile', 'Профиль')
|
||
.replace('/history', 'История')
|
||
.replace('/crop-photo', 'Обрезка фото');
|
||
|
||
// Если это добавление стикера в пак, извлекаем название пака
|
||
if (screenName.includes('/add-sticker/')) {
|
||
const packName = screenName.split('/add-sticker/')[1];
|
||
screenName = `Добавление стикера в пак: ${packName}`;
|
||
}
|
||
}
|
||
|
||
// Отправляем событие просмотра экрана
|
||
trackScreenView(screenName);
|
||
}, [location.pathname]);
|
||
|
||
return (
|
||
<Routes>
|
||
{/* Онбординг */}
|
||
<Route path="/onboarding">
|
||
<Route index element={<Navigate to="/onboarding/welcome" replace />} />
|
||
<Route path="welcome" element={
|
||
<Suspense fallback={<LoadingScreen />}>
|
||
<OnboardingWelcome />
|
||
</Suspense>
|
||
} />
|
||
<Route path="how-to" element={
|
||
<Suspense fallback={<LoadingScreen />}>
|
||
<OnboardingHowTo />
|
||
</Suspense>
|
||
} />
|
||
<Route path="sticker-packs" element={
|
||
<Suspense fallback={<LoadingScreen />}>
|
||
<OnboardingStickerPacks />
|
||
</Suspense>
|
||
} />
|
||
<Route path="terms" element={
|
||
<Suspense fallback={<LoadingScreen />}>
|
||
<TermsAndConditions />
|
||
</Suspense>
|
||
} />
|
||
</Route>
|
||
|
||
{/* Основные экраны */}
|
||
<Route element={<Layout>
|
||
<Suspense fallback={<LoadingScreen />}>
|
||
<Outlet />
|
||
</Suspense>
|
||
</Layout>}>
|
||
<Route path="/" element={<Home />} />
|
||
<Route path="/create" element={<CreateSticker />} />
|
||
<Route path="/gallery" element={<Gallery />} />
|
||
<Route path="/packs" element={<StickerPacks />} />
|
||
<Route path="/create-sticker-pack" element={<CreateStickerPack />} />
|
||
<Route path="/add-sticker/:packName" element={<AddStickerToPackScreen />} />
|
||
<Route path="/profile" element={<Profile />} />
|
||
<Route path="/history" element={<History />} />
|
||
<Route path="/crop-photo" element={<CropPhoto />} />
|
||
</Route>
|
||
</Routes>
|
||
);
|
||
};
|
||
|
||
const App: React.FC = () => {
|
||
return (
|
||
<BrowserRouter>
|
||
<AppContent />
|
||
</BrowserRouter>
|
||
);
|
||
};
|
||
|
||
export default App;
|