feat: add WebBackButton to all sub-pages, widen renew page layout

- New WebBackButton component: visible on web, hidden in Telegram
  (native back button handles navigation there)
- Added to: Subscription detail, SubscriptionPurchase, RenewSubscription
- RenewSubscription: removed max-w-lg, grid layout for period cards
This commit is contained in:
c0mrade
2026-03-24 14:01:55 +03:00
parent f1cb9e5c66
commit 31d0953c23
4 changed files with 73 additions and 27 deletions

View File

@@ -0,0 +1,32 @@
import { Link } from 'react-router';
import { usePlatform } from '../platform';
import { BackIcon } from './icons';
interface WebBackButtonProps {
to: string;
replace?: boolean;
className?: string;
}
/**
* Back button visible only on web platform.
* Hidden in Telegram Mini App — native back button handles navigation there.
*/
export function WebBackButton({ to, replace, className }: WebBackButtonProps) {
const { platform } = usePlatform();
if (platform === 'telegram') return null;
return (
<Link
to={to}
replace={replace}
className={
className ||
'flex h-10 w-10 items-center justify-center rounded-xl border border-dark-700 bg-dark-800 transition-colors hover:border-dark-600'
}
>
<BackIcon />
</Link>
);
}

View File

@@ -8,6 +8,7 @@ import { getGlassColors } from '../utils/glassTheme';
import { useCurrency } from '../hooks/useCurrency'; import { useCurrency } from '../hooks/useCurrency';
import { useHaptic } from '../platform'; import { useHaptic } from '../platform';
import InsufficientBalancePrompt from '../components/InsufficientBalancePrompt'; import InsufficientBalancePrompt from '../components/InsufficientBalancePrompt';
import { WebBackButton } from '../components/WebBackButton';
export default function RenewSubscription() { export default function RenewSubscription() {
const { subscriptionId } = useParams<{ subscriptionId: string }>(); const { subscriptionId } = useParams<{ subscriptionId: string }>();
@@ -97,8 +98,10 @@ export default function RenewSubscription() {
const missingAmount = insufficientMatch ? Number(insufficientMatch[1]) : null; const missingAmount = insufficientMatch ? Number(insufficientMatch[1]) : null;
return ( return (
<div className="mx-auto max-w-lg space-y-5 p-4"> <div className="space-y-5">
{/* Title */} {/* Title */}
<div className="flex items-center gap-3">
<WebBackButton to={`/subscriptions/${subId}`} />
<div> <div>
<h1 className="text-2xl font-bold" style={{ color: g.text }}> <h1 className="text-2xl font-bold" style={{ color: g.text }}>
{t('subscription.extend', 'Продлить подписку')} {t('subscription.extend', 'Продлить подписку')}
@@ -109,6 +112,7 @@ export default function RenewSubscription() {
</p> </p>
)} )}
</div> </div>
</div>
{/* Balance */} {/* Balance */}
<div <div
@@ -134,7 +138,7 @@ export default function RenewSubscription() {
</p> </p>
</div> </div>
) : ( ) : (
<div className="space-y-2"> <div className="grid grid-cols-1 gap-3 sm:grid-cols-2">
{options.map((option) => { {options.map((option) => {
const isSelected = selectedPeriod === option.period_days; const isSelected = selectedPeriod === option.period_days;
const canAfford = balanceKopeks >= option.price_kopeks; const canAfford = balanceKopeks >= option.price_kopeks;

View File

@@ -3,6 +3,7 @@ import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useNavigate, useParams } from 'react-router'; import { useNavigate, useParams } from 'react-router';
import { subscriptionApi } from '../api/subscription'; import { subscriptionApi } from '../api/subscription';
import { WebBackButton } from '../components/WebBackButton';
import TrafficProgressBar from '../components/dashboard/TrafficProgressBar'; import TrafficProgressBar from '../components/dashboard/TrafficProgressBar';
import { HoverBorderGradient } from '../components/ui/hover-border-gradient'; import { HoverBorderGradient } from '../components/ui/hover-border-gradient';
import { useTrafficZone } from '../hooks/useTrafficZone'; import { useTrafficZone } from '../hooks/useTrafficZone';
@@ -480,12 +481,15 @@ export default function Subscription() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
{/* Page title — native Telegram back button handles navigation */} {/* Page title */}
<div className="flex items-center gap-3">
<WebBackButton to="/subscriptions" />
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl"> <h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">
{isMultiTariff && subscription?.tariff_name {isMultiTariff && subscription?.tariff_name
? subscription.tariff_name ? subscription.tariff_name
: t('subscription.title')} : t('subscription.title')}
</h1> </h1>
</div>
{/* Current Subscription */} {/* Current Subscription */}
{subscription ? ( {subscription ? (

View File

@@ -5,6 +5,7 @@ import { useNavigate, useSearchParams } from 'react-router';
import { AxiosError } from 'axios'; import { AxiosError } from 'axios';
import { subscriptionApi } from '../api/subscription'; import { subscriptionApi } from '../api/subscription';
import { promoApi } from '../api/promo'; import { promoApi } from '../api/promo';
import { WebBackButton } from '../components/WebBackButton';
import { getGlassColors } from '../utils/glassTheme'; import { getGlassColors } from '../utils/glassTheme';
import { useTheme } from '../hooks/useTheme'; import { useTheme } from '../hooks/useTheme';
import type { import type {
@@ -407,7 +408,11 @@ export default function SubscriptionPurchase() {
return ( return (
<div className="space-y-6"> <div className="space-y-6">
{/* Header — native Telegram back button handles navigation */} {/* Header */}
<div className="flex items-center gap-3">
<WebBackButton
to={subscriptionId ? `/subscriptions/${subscriptionId}` : '/subscriptions'}
/>
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl"> <h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">
{isMultiTariff && !subscriptionId {isMultiTariff && !subscriptionId
? t('subscription.newTariff', 'Новый тариф') ? t('subscription.newTariff', 'Новый тариф')
@@ -417,6 +422,7 @@ export default function SubscriptionPurchase() {
? t('subscription.extend') ? t('subscription.extend')
: t('subscription.getSubscription')} : t('subscription.getSubscription')}
</h1> </h1>
</div>
{/* Tariffs Section */} {/* Tariffs Section */}
{isTariffsMode && tariffs.length > 0 && ( {isTariffsMode && tariffs.length > 0 && (