StickerAI-Front/src/App.tsx

156 lines
6.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;