mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
fix(navigation): single-tariff /subscriptions/:id deep-link shows Close, not Back
Refines3c2f650— that commit broke the loop by suppressing the single-tariff redirect on idx=0, but left the BackButton visible. The user still saw Back on the detail page and needed two taps (Back → Close) to exit. Серёжа's report was specifically that Back should not appear at all when you land on your only subscription via a bot button. Move the decision up to TelegramBackButton: - Subscribe to the existing ['subscriptions-list'] query (deduped by React Query, so no extra fetch). - On /subscriptions/:id, when multi_tariff_enabled is false and there is no in-app history (idx=0 deep-link entry), hide the BackButton. Telegram then surfaces its native Close (X) in the header. - Multi-tariff users still see BackButton on /subscriptions/:id deep-links because their /subscriptions list is meaningful (they have many subs). The2bcba3bfallback-to-parent behaviour remains intact for unrelated deep-links like /balance/top-up, /admin/*, etc. Revert the defensive guard in Subscriptions.tsx — the loop can no longer be triggered because no BackButton is shown to trigger it. Behaviour summary: flow BackButton exit cost -------------------------------------- ---------- --------- deep-link → /subscriptions/:id (1T) hidden Close, 1 tap / → /subscriptions → /subscriptions/:id shown Back → /, 1 tap deep-link → /balance/top-up shown Back → /balance ✓ deep-link → /subscriptions/:id (multi) shown Back → /subscriptions list Reported by Серёжа, bugs topic #599679.
This commit is contained in:
@@ -6,6 +6,7 @@ import {
|
||||
onBackButtonClick,
|
||||
offBackButtonClick,
|
||||
} from '@telegram-apps/sdk-react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import Twemoji from 'react-twemoji';
|
||||
import App from './App';
|
||||
import { ErrorBoundary } from './components/ErrorBoundary';
|
||||
@@ -16,6 +17,7 @@ import { ToastProvider } from './components/Toast';
|
||||
import { TooltipProvider } from './components/primitives/Tooltip';
|
||||
import { isInTelegramWebApp } from './hooks/useTelegramSDK';
|
||||
import { hasInAppHistory, getFallbackParentPath } from './utils/navigation';
|
||||
import { subscriptionApi } from './api/subscription';
|
||||
|
||||
const TWEMOJI_OPTIONS = { className: 'twemoji', folder: 'svg', ext: '.svg' } as const;
|
||||
|
||||
@@ -26,6 +28,13 @@ const TWEMOJI_OPTIONS = { className: 'twemoji', folder: 'svg', ext: '.svg' } as
|
||||
/** Pages reachable from bottom nav — treat as top-level (no back button). */
|
||||
const BOTTOM_NAV_PATHS = ['/', '/subscriptions', '/balance', '/referral', '/support', '/wheel'];
|
||||
|
||||
/** Matches /subscriptions/:numericId — single-tariff users land here from
|
||||
* bot deep-links, but their /subscriptions list is empty (the list view
|
||||
* auto-redirects them straight back to this page). Pressing Back would loop
|
||||
* back to detail, so on a deep-link entry (idx=0) we hide the back button
|
||||
* and let Telegram surface its native Close (X) button instead. */
|
||||
const SUBSCRIPTION_DETAIL_RE = /^\/subscriptions\/\d+\/?$/;
|
||||
|
||||
function TelegramBackButton() {
|
||||
const location = useLocation();
|
||||
const navigate = useNavigate();
|
||||
@@ -34,16 +43,30 @@ function TelegramBackButton() {
|
||||
const pathnameRef = useRef(location.pathname);
|
||||
pathnameRef.current = location.pathname;
|
||||
|
||||
// Share the subscriptions-list query with the page-level components.
|
||||
// React Query dedupes by key so this does not cause an extra fetch when
|
||||
// Subscriptions/Subscription/Dashboard pages mount.
|
||||
const { data: subData } = useQuery({
|
||||
queryKey: ['subscriptions-list'],
|
||||
queryFn: () => subscriptionApi.getSubscriptions(),
|
||||
staleTime: 30_000,
|
||||
// Don't fetch outside Telegram — the cabinet still loads on the web.
|
||||
enabled: isInTelegramWebApp(),
|
||||
});
|
||||
const isMultiTariff = subData?.multi_tariff_enabled ?? false;
|
||||
|
||||
useEffect(() => {
|
||||
const isTopLevel = location.pathname === '' || BOTTOM_NAV_PATHS.includes(location.pathname);
|
||||
const isSingleTariffDetailDeepLink =
|
||||
!isMultiTariff && SUBSCRIPTION_DETAIL_RE.test(location.pathname) && !hasInAppHistory();
|
||||
try {
|
||||
if (isTopLevel) {
|
||||
if (isTopLevel || isSingleTariffDetailDeepLink) {
|
||||
hideBackButton();
|
||||
} else {
|
||||
showBackButton();
|
||||
}
|
||||
} catch {}
|
||||
}, [location]);
|
||||
}, [location, isMultiTariff]);
|
||||
|
||||
// Stable handler — ref prevents re-subscription on every render
|
||||
const handler = useCallback(() => {
|
||||
|
||||
@@ -9,7 +9,6 @@ import { getGlassColors } from '../utils/glassTheme';
|
||||
import { useAuthStore } from '../store/auth';
|
||||
import SubscriptionListCard from '../components/subscription/SubscriptionListCard';
|
||||
import TrialOfferCard from '../components/dashboard/TrialOfferCard';
|
||||
import { hasInAppHistory } from '../utils/navigation';
|
||||
|
||||
function EmptyState({ onBuy }: { onBuy: () => void }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -107,11 +106,8 @@ export default function Subscriptions() {
|
||||
},
|
||||
});
|
||||
|
||||
// Single-tariff mode with one subscription: skip list, go directly to detail.
|
||||
// Skip the redirect when the user just hit the Telegram BackButton from
|
||||
// /subscriptions/:id — that lands us here with idx=0, and redirecting back
|
||||
// to the detail page creates a Back-button loop the user can't escape (#599679).
|
||||
if (data && !isMultiTariff && subscriptions.length === 1 && hasInAppHistory()) {
|
||||
// Single-tariff mode with one subscription: skip list, go directly to detail
|
||||
if (data && !isMultiTariff && subscriptions.length === 1) {
|
||||
return <Navigate to={`/subscriptions/${subscriptions[0].id}`} replace />;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user