mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-29 18:13:47 +00:00
fix(navigation): single-tariff subscription detail всегда Close, не Back
Регрессия после a62d689: Back прятался только при deep-link входе
(depthRef === 0). При внутреннем переходе на /subscriptions/:id (depth > 0)
показывался Back, а в single-tariff «назад» уходил в /subscriptions, который
тут же редиректит обратно на деталь (Subscriptions.tsx) — петля, и юзер видел
Back вместо Close.
Решение depth-независимое: если список-редирект всё равно отбрасывает на эту
же страницу (single-tariff, ≤1 подписки = listRedirectsToDetail, инверсия
listIsSafe из обработчика), деталь — это верхний экран. Прячем Back всегда,
Telegram показывает нативный Close. Петля невозможна по построению: без кнопки
Back обработчик navigate(-1) в редиректящий список просто не вызвать.
Multi-tariff и >1 подписки сохраняют реальный Back к осмысленному списку.
This commit is contained in:
@@ -28,11 +28,11 @@ const TWEMOJI_OPTIONS = { className: 'twemoji', folder: 'svg', ext: '.svg' } as
|
|||||||
/** Pages reachable from bottom nav — treat as top-level (no back button). */
|
/** Pages reachable from bottom nav — treat as top-level (no back button). */
|
||||||
const BOTTOM_NAV_PATHS = ['/', '/subscriptions', '/balance', '/referral', '/support', '/wheel'];
|
const BOTTOM_NAV_PATHS = ['/', '/subscriptions', '/balance', '/referral', '/support', '/wheel'];
|
||||||
|
|
||||||
/** Matches /subscriptions/:numericId. Single-tariff users land here straight
|
/** Matches /subscriptions/:numericId. When the user has a single tariff and at
|
||||||
* from bot deep-links, and their /subscriptions list auto-redirects right back
|
* most one subscription, the /subscriptions list auto-redirects straight back
|
||||||
* to this page (Subscriptions.tsx). So on a genuine deep-link entry (in-app
|
* here (Subscriptions.tsx), so this page is effectively top-level: we hide the
|
||||||
* navigation depth 0) we hide the back button and let Telegram surface its
|
* back button and let Telegram surface its native Close (X). Multi-tariff users
|
||||||
* native Close (X); when there IS in-app history we show it and navigate back. */
|
* (or anyone with >1 subscription) keep a real Back to their meaningful list. */
|
||||||
const SUBSCRIPTION_DETAIL_RE = /^\/subscriptions\/\d+\/?$/;
|
const SUBSCRIPTION_DETAIL_RE = /^\/subscriptions\/\d+\/?$/;
|
||||||
|
|
||||||
function TelegramBackButton() {
|
function TelegramBackButton() {
|
||||||
@@ -71,27 +71,39 @@ function TelegramBackButton() {
|
|||||||
enabled: isInTelegramWebApp(),
|
enabled: isInTelegramWebApp(),
|
||||||
});
|
});
|
||||||
const isMultiTariff = subData?.multi_tariff_enabled ?? false;
|
const isMultiTariff = subData?.multi_tariff_enabled ?? false;
|
||||||
|
const subsCount = subData?.subscriptions?.length ?? 0;
|
||||||
|
// The /subscriptions list silently redirects straight back to the open detail
|
||||||
|
// page when there is a single tariff and at most one subscription
|
||||||
|
// (Subscriptions.tsx). In that mode the detail page IS the top-level screen —
|
||||||
|
// there is no meaningful "back" target. Inverse of the handler's `listIsSafe`.
|
||||||
|
// Defaults to true on a cold cache (isMultiTariff=false, subsCount=0): hiding
|
||||||
|
// Back is fail-closed — far better than briefly arming the looping Back.
|
||||||
|
const listRedirectsToDetail = !isMultiTariff && subsCount <= 1;
|
||||||
|
|
||||||
// Refs so the stable back handler (memoised with []) reads fresh values
|
// Refs so the stable back handler (memoised with []) reads fresh values
|
||||||
// without re-subscribing — re-subscription lets a component's local handler
|
// without re-subscribing — re-subscription lets a component's local handler
|
||||||
// overwrite ours via Telegram's singleton onBackButtonClick (issue #436).
|
// overwrite ours via Telegram's singleton onBackButtonClick (issue #436).
|
||||||
const isMultiTariffRef = useRef(isMultiTariff);
|
const isMultiTariffRef = useRef(isMultiTariff);
|
||||||
isMultiTariffRef.current = isMultiTariff;
|
isMultiTariffRef.current = isMultiTariff;
|
||||||
const subsCountRef = useRef(subData?.subscriptions?.length ?? 0);
|
const subsCountRef = useRef(subsCount);
|
||||||
subsCountRef.current = subData?.subscriptions?.length ?? 0;
|
subsCountRef.current = subsCount;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isTopLevel = location.pathname === '' || BOTTOM_NAV_PATHS.includes(location.pathname);
|
const isTopLevel = location.pathname === '' || BOTTOM_NAV_PATHS.includes(location.pathname);
|
||||||
const isSingleTariffDetailDeepLink =
|
// Depth-independent on purpose: whether the user deep-linked in or navigated
|
||||||
!isMultiTariff && SUBSCRIPTION_DETAIL_RE.test(location.pathname) && depthRef.current === 0;
|
// here in-app, a single-tariff detail whose list just bounces back has no
|
||||||
|
// real "back" target. Showing Back here is exactly what looped through the
|
||||||
|
// redirecting /subscriptions list (#436); hiding it always surfaces Close.
|
||||||
|
const isRedirectingSubscriptionDetail =
|
||||||
|
listRedirectsToDetail && SUBSCRIPTION_DETAIL_RE.test(location.pathname);
|
||||||
try {
|
try {
|
||||||
if (isTopLevel || isSingleTariffDetailDeepLink) {
|
if (isTopLevel || isRedirectingSubscriptionDetail) {
|
||||||
hideBackButton();
|
hideBackButton();
|
||||||
} else {
|
} else {
|
||||||
showBackButton();
|
showBackButton();
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
}, [location, isMultiTariff]);
|
}, [location, listRedirectsToDetail]);
|
||||||
|
|
||||||
// Stable handler — ref prevents re-subscription on every render
|
// Stable handler — ref prevents re-subscription on every render
|
||||||
const handler = useCallback(() => {
|
const handler = useCallback(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user