Files
aiform_prod/frontend/src/App.tsx
Fedor 06b89d20e7 Support: маршрут /support на страницу чата поддержки
- App.tsx: добавлен импорт страницы Support и роутинг pathname === '/support' на компонент Support.
- При клике на иконку «Поддержка» в нижнем баре теперь открывается список обращений и чат, а не форма «Мои обращения».
2026-02-27 10:13:19 +03:00

96 lines
3.4 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 { useState, useEffect, useCallback, useRef } from 'react';
import ClaimForm from './pages/ClaimForm';
import HelloAuth from './pages/HelloAuth';
import Profile from './pages/Profile';
import Support from './pages/Support';
import BottomBar from './components/BottomBar';
import './App.css';
import { miniappLog, miniappSendLogs } from './utils/miniappLogger';
function App() {
const [pathname, setPathname] = useState<string>(() => {
const p = window.location.pathname || '';
if (p !== '/hello' && !p.startsWith('/hello')) return '/hello';
return p;
});
const [avatarUrl, setAvatarUrl] = useState<string>(() => localStorage.getItem('user_avatar_url') || '');
const lastRouteTsRef = useRef<number>(Date.now());
const lastPathRef = useRef<string>(pathname);
useEffect(() => {
const path = window.location.pathname || '/';
if (path !== '/hello' && !path.startsWith('/hello')) {
window.history.replaceState({}, '', '/hello' + (window.location.search || '') + (window.location.hash || ''));
}
}, []);
useEffect(() => {
const onPopState = () => setPathname(window.location.pathname || '');
window.addEventListener('popstate', onPopState);
return () => window.removeEventListener('popstate', onPopState);
}, []);
// Логируем смену маршрута + ловим быстрый возврат на /hello (симптом бага)
useEffect(() => {
const now = Date.now();
const prev = lastPathRef.current;
lastPathRef.current = pathname;
lastRouteTsRef.current = now;
miniappLog('route', { prev, next: pathname });
if (pathname.startsWith('/hello') && !prev.startsWith('/hello')) {
// Вернулись на /hello: отправим дамп, чтобы поймать “ложится”
void miniappSendLogs('returned_to_hello');
}
}, [pathname]);
// Ловим клики в первые 2с после смены маршрута (ghost click / попадание в бар)
useEffect(() => {
const onClickCapture = (e: MouseEvent) => {
const dt = Date.now() - lastRouteTsRef.current;
if (dt > 2000) return;
const t = e.target as HTMLElement | null;
const inBar = !!t?.closest?.('.app-bottom-bar');
miniappLog('click_capture', {
dtFromRouteMs: dt,
inBottomBar: inBar,
tag: t?.tagName,
id: t?.id,
class: t?.className,
x: (e as MouseEvent).clientX,
y: (e as MouseEvent).clientY,
});
};
window.addEventListener('click', onClickCapture, true);
return () => window.removeEventListener('click', onClickCapture, true);
}, []);
useEffect(() => {
setAvatarUrl(localStorage.getItem('user_avatar_url') || '');
}, [pathname]);
const isNewClaimPage = pathname === '/new';
const navigateTo = useCallback((path: string) => {
window.history.pushState({}, '', path);
setPathname(path);
}, []);
return (
<div className="App">
{pathname === '/profile' ? (
<Profile onNavigate={navigateTo} />
) : pathname === '/support' ? (
<Support onNavigate={navigateTo} />
) : pathname.startsWith('/hello') ? (
<HelloAuth onAvatarChange={setAvatarUrl} onNavigate={navigateTo} />
) : (
<ClaimForm forceNewClaim={isNewClaimPage} />
)}
<BottomBar currentPath={pathname} avatarUrl={avatarUrl || undefined} onNavigate={navigateTo} />
</div>
);
}
export default App;