mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
fix(navigation): make Telegram back button work on deep-link entry
Bot deep-links open the Mini App directly on nested routes (/admin, /balance/top-up, /info, /profile, ...) where React Router history has a single entry, so navigate(-1) was a no-op and the native back button looked dead. Fall back to the derived parent route when there is no in-app history (window.history.state.idx === 0).
This commit is contained in:
@@ -15,6 +15,7 @@ import { WebSocketProvider } from './providers/WebSocketProvider';
|
||||
import { ToastProvider } from './components/Toast';
|
||||
import { TooltipProvider } from './components/primitives/Tooltip';
|
||||
import { isInTelegramWebApp } from './hooks/useTelegramSDK';
|
||||
import { hasInAppHistory, getFallbackParentPath } from './utils/navigation';
|
||||
|
||||
const TWEMOJI_OPTIONS = { className: 'twemoji', folder: 'svg', ext: '.svg' } as const;
|
||||
|
||||
@@ -30,6 +31,8 @@ function TelegramBackButton() {
|
||||
const navigate = useNavigate();
|
||||
const navigateRef = useRef(navigate);
|
||||
navigateRef.current = navigate;
|
||||
const pathnameRef = useRef(location.pathname);
|
||||
pathnameRef.current = location.pathname;
|
||||
|
||||
useEffect(() => {
|
||||
const isTopLevel = location.pathname === '' || BOTTOM_NAV_PATHS.includes(location.pathname);
|
||||
@@ -44,7 +47,14 @@ function TelegramBackButton() {
|
||||
|
||||
// Stable handler — ref prevents re-subscription on every render
|
||||
const handler = useCallback(() => {
|
||||
// When opened via a bot deep-link directly on a nested route, there is no
|
||||
// in-app history and navigate(-1) is a no-op — the back button looks dead.
|
||||
// Fall back to the parent route so it always navigates somewhere sensible.
|
||||
if (hasInAppHistory()) {
|
||||
navigateRef.current(-1);
|
||||
} else {
|
||||
navigateRef.current(getFallbackParentPath(pathnameRef.current), { replace: true });
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
38
src/utils/navigation.ts
Normal file
38
src/utils/navigation.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Navigation helpers for back-button behavior.
|
||||
*
|
||||
* The Telegram Mini App (and any deep-link entry) can be opened directly on a
|
||||
* nested route — e.g. a bot button that opens `/admin` or `/balance/top-up`.
|
||||
* In that case React Router's history stack holds a single entry, so a plain
|
||||
* `navigate(-1)` has nothing to go back to and the back button appears dead.
|
||||
* These helpers let callers detect that situation and fall back to a sensible
|
||||
* parent route instead.
|
||||
*/
|
||||
|
||||
/**
|
||||
* React Router stores the current position in the history stack on
|
||||
* `window.history.state.idx`. The first/entry record is `0`. When `idx === 0`
|
||||
* there is no in-app history to go back to (the page is the deep-link entry).
|
||||
*/
|
||||
export function hasInAppHistory(): boolean {
|
||||
const idx = (window.history.state as { idx?: number } | null)?.idx ?? 0;
|
||||
return idx > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Derive a parent route by dropping the last path segment.
|
||||
*
|
||||
* /admin/users/123 → /admin/users
|
||||
* /balance/top-up → /balance
|
||||
* /info → /
|
||||
* / → /
|
||||
*
|
||||
* Used as the back-button target when there is no in-app history. If the
|
||||
* derived path is not a real route the app's catch-all redirects to `/`,
|
||||
* so the user is never left stuck.
|
||||
*/
|
||||
export function getFallbackParentPath(pathname: string): string {
|
||||
const segments = pathname.replace(/\/+$/, '').split('/').filter(Boolean);
|
||||
const parent = segments.slice(0, -1);
|
||||
return parent.length ? '/' + parent.join('/') : '/';
|
||||
}
|
||||
Reference in New Issue
Block a user