2026-02-23 11:31:52 +03:00
|
|
|
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
2026-02-21 22:08:30 +03:00
|
|
|
|
import ClaimForm from './pages/ClaimForm';
|
|
|
|
|
|
import HelloAuth from './pages/HelloAuth';
|
2026-02-24 16:17:59 +03:00
|
|
|
|
import Profile from './pages/Profile';
|
2026-02-27 10:13:19 +03:00
|
|
|
|
import Support from './pages/Support';
|
2026-02-21 22:08:30 +03:00
|
|
|
|
import BottomBar from './components/BottomBar';
|
|
|
|
|
|
import './App.css';
|
2026-02-23 11:31:52 +03:00
|
|
|
|
import { miniappLog, miniappSendLogs } from './utils/miniappLogger';
|
2025-10-24 12:02:17 +03:00
|
|
|
|
|
|
|
|
|
|
function App() {
|
2026-02-24 16:17:59 +03:00
|
|
|
|
const [pathname, setPathname] = useState<string>(() => {
|
|
|
|
|
|
const p = window.location.pathname || '';
|
|
|
|
|
|
if (p !== '/hello' && !p.startsWith('/hello')) return '/hello';
|
|
|
|
|
|
return p;
|
|
|
|
|
|
});
|
2026-02-21 22:08:30 +03:00
|
|
|
|
const [avatarUrl, setAvatarUrl] = useState<string>(() => localStorage.getItem('user_avatar_url') || '');
|
2026-02-23 11:31:52 +03:00
|
|
|
|
const lastRouteTsRef = useRef<number>(Date.now());
|
|
|
|
|
|
const lastPathRef = useRef<string>(pathname);
|
2026-02-21 22:08:30 +03:00
|
|
|
|
|
2026-02-24 16:17:59 +03:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
const path = window.location.pathname || '/';
|
|
|
|
|
|
if (path !== '/hello' && !path.startsWith('/hello')) {
|
|
|
|
|
|
window.history.replaceState({}, '', '/hello' + (window.location.search || '') + (window.location.hash || ''));
|
|
|
|
|
|
}
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
2026-02-21 22:08:30 +03:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
const onPopState = () => setPathname(window.location.pathname || '');
|
|
|
|
|
|
window.addEventListener('popstate', onPopState);
|
|
|
|
|
|
return () => window.removeEventListener('popstate', onPopState);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
2026-02-23 11:31:52 +03:00
|
|
|
|
// Логируем смену маршрута + ловим быстрый возврат на /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);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
2026-02-21 22:08:30 +03:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
setAvatarUrl(localStorage.getItem('user_avatar_url') || '');
|
|
|
|
|
|
}, [pathname]);
|
|
|
|
|
|
|
|
|
|
|
|
const isNewClaimPage = pathname === '/new';
|
|
|
|
|
|
|
|
|
|
|
|
const navigateTo = useCallback((path: string) => {
|
|
|
|
|
|
window.history.pushState({}, '', path);
|
|
|
|
|
|
setPathname(path);
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
2025-10-24 12:02:17 +03:00
|
|
|
|
return (
|
2025-10-24 16:19:58 +03:00
|
|
|
|
<div className="App">
|
2026-02-24 16:17:59 +03:00
|
|
|
|
{pathname === '/profile' ? (
|
|
|
|
|
|
<Profile onNavigate={navigateTo} />
|
2026-02-27 10:13:19 +03:00
|
|
|
|
) : pathname === '/support' ? (
|
|
|
|
|
|
<Support onNavigate={navigateTo} />
|
2026-02-24 16:17:59 +03:00
|
|
|
|
) : pathname.startsWith('/hello') ? (
|
2026-02-21 22:08:30 +03:00
|
|
|
|
<HelloAuth onAvatarChange={setAvatarUrl} onNavigate={navigateTo} />
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<ClaimForm forceNewClaim={isNewClaimPage} />
|
|
|
|
|
|
)}
|
2026-02-24 16:17:59 +03:00
|
|
|
|
<BottomBar currentPath={pathname} avatarUrl={avatarUrl || undefined} onNavigate={navigateTo} />
|
2025-10-24 12:02:17 +03:00
|
|
|
|
</div>
|
2026-02-21 22:08:30 +03:00
|
|
|
|
);
|
2025-10-24 12:02:17 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-21 22:08:30 +03:00
|
|
|
|
export default App;
|