- App.tsx: добавлен импорт страницы Support и роутинг pathname === '/support' на компонент Support. - При клике на иконку «Поддержка» в нижнем баре теперь открывается список обращений и чат, а не форма «Мои обращения».
96 lines
3.4 KiB
TypeScript
96 lines
3.4 KiB
TypeScript
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;
|