import { useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { Navigate, useNavigate } from 'react-router'; import { useTranslation } from 'react-i18next'; import { ClipboardIcon, PlusIcon } from '@/components/icons'; import { subscriptionApi } from '../api/subscription'; import { balanceApi } from '../api/balance'; import { useTheme } from '../hooks/useTheme'; import { getGlassColors } from '../utils/glassTheme'; import { useAuthStore } from '../store/auth'; import SubscriptionListCard from '../components/subscription/SubscriptionListCard'; import TrialOfferCard from '../components/dashboard/TrialOfferCard'; function EmptyState({ onBuy }: { onBuy: () => void }) { const { t } = useTranslation(); const { isDark } = useTheme(); const g = getGlassColors(isDark); return (

{t('subscriptions.empty', 'Нет подписок')}

{t('subscriptions.emptyDesc', 'У вас пока нет активных подписок')}

); } export default function Subscriptions() { const { t } = useTranslation(); const navigate = useNavigate(); const { isDark } = useTheme(); const g = getGlassColors(isDark); const queryClient = useQueryClient(); const refreshUser = useAuthStore((state) => state.refreshUser); const [trialError, setTrialError] = useState(null); const { data, isLoading } = useQuery({ queryKey: ['subscriptions-list'], queryFn: () => subscriptionApi.getSubscriptions(), staleTime: 30_000, refetchOnMount: 'always', }); const subscriptions = data?.subscriptions ?? []; const isMultiTariff = data?.multi_tariff_enabled ?? false; const hasNoSubscriptions = !isLoading && subscriptions.length === 0; // Есть ли хотя бы одна НАСТОЯЩАЯ (платная, не триал) живая подписка. От этого // зависит CTA: «+ Купить ещё» — только если уже есть платная; иначе показываем // явную «Посмотреть тарифы и купить подписку» (триал/истёкшие — это ещё не покупка). const hasActivePaid = subscriptions.some( (s) => !s.is_trial && (s.status === 'active' || s.status === 'limited'), ); // Если у юзера нет подписок — проверяем доступность триала, иначе // (в multi-tariff) ему вообще негде увидеть оффер. const { data: trialInfo, isLoading: trialLoading } = useQuery({ queryKey: ['trial-info'], queryFn: () => subscriptionApi.getTrialInfo(), enabled: hasNoSubscriptions, staleTime: 30_000, }); const { data: balanceData } = useQuery({ queryKey: ['balance'], queryFn: balanceApi.getBalance, enabled: hasNoSubscriptions && !!trialInfo?.is_available, staleTime: 30_000, }); const activateTrialMutation = useMutation({ mutationFn: () => subscriptionApi.activateTrial(), onSuccess: () => { setTrialError(null); queryClient.invalidateQueries({ queryKey: ['subscription'] }); queryClient.invalidateQueries({ queryKey: ['subscriptions-list'] }); queryClient.invalidateQueries({ queryKey: ['trial-info'] }); queryClient.invalidateQueries({ queryKey: ['balance'] }); queryClient.invalidateQueries({ queryKey: ['purchase-options'] }); refreshUser(); }, onError: (error: { response?: { data?: { detail?: string } } }) => { setTrialError(error.response?.data?.detail || t('common.error')); }, }); // Single-tariff mode with one subscription: skip list, go directly to detail if (data && !isMultiTariff && subscriptions.length === 1) { return ; } return (
{/* Header */}

{t('subscriptions.title', 'Мои подписки')}

{/* «+ Купить ещё» — только если уже есть платная активная подписка */} {!isLoading && hasActivePaid && ( )}
{/* Есть подписки, но платной активной нет (только триал/истёкшие) — даём ЯВНУЮ primary-кнопку покупки: мы продаём подписки. */} {!isLoading && subscriptions.length > 0 && !hasActivePaid && ( )} {/* Loading */} {isLoading && (
{[1, 2].map((i) => (
))}
)} {/* Empty state: показываем триал, если доступен; иначе — обычный empty */} {hasNoSubscriptions && !trialLoading && trialInfo?.is_available && (
{/* Новый пользователь не обязан активировать триал, чтобы попасть в витрину — даём явный путь к покупке подписки. Раньше при доступном триале это был единственный экран без кнопки «Купить» (Telegram-баг #605056/#605063). */}
)} {hasNoSubscriptions && !trialLoading && !trialInfo?.is_available && ( navigate('/subscription/purchase')} /> )} {/* Subscription grid */} {subscriptions.length > 0 && (
{subscriptions.map((sub) => ( navigate(`/subscriptions/${sub.id}`)} /> ))}
)}
); }