diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 5fa39d9..b04cde4 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -195,7 +195,12 @@ export default function Dashboard() { refreshTrafficMutation.mutate(); }, [subscription, refreshTrafficMutation]); - const hasNoSubscription = subscriptionResponse?.has_subscription === false && !subLoading; + // В multi-tariff /cabinet/subscription отключён, поэтому subscriptionResponse=undefined. + // Используем список из /cabinet/subscriptions/list — пустой массив означает «нет подписок», + // и тогда показываем TrialOfferCard. Без этой ветки multi-tariff юзер никогда не видел триал. + const hasNoSubscription = isMultiTariff + ? multiSubData !== undefined && (multiSubData.subscriptions?.length ?? 0) === 0 + : subscriptionResponse?.has_subscription === false && !subLoading; // Show onboarding for new users after data loads useEffect(() => { diff --git a/src/pages/Subscriptions.tsx b/src/pages/Subscriptions.tsx index 1b2e600..9fb032f 100644 --- a/src/pages/Subscriptions.tsx +++ b/src/pages/Subscriptions.tsx @@ -1,10 +1,14 @@ -import { useQuery } from '@tanstack/react-query'; +import { useState } from 'react'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { Navigate, useNavigate } from 'react-router'; import { useTranslation } from 'react-i18next'; 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(); @@ -55,6 +59,9 @@ export default function Subscriptions() { 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'], @@ -65,6 +72,39 @@ export default function Subscriptions() { const subscriptions = data?.subscriptions ?? []; const isMultiTariff = data?.multi_tariff_enabled ?? false; + const hasNoSubscriptions = !isLoading && subscriptions.length === 0; + + // Если у юзера нет подписок — проверяем доступность триала, иначе + // (в 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) { @@ -115,8 +155,17 @@ export default function Subscriptions() { )} - {/* Empty state */} - {!isLoading && subscriptions.length === 0 && ( + {/* Empty state: показываем триал, если доступен; иначе — обычный empty */} + {hasNoSubscriptions && !trialLoading && trialInfo?.is_available && ( + + )} + {hasNoSubscriptions && !trialLoading && !trialInfo?.is_available && ( navigate('/subscription/purchase')} /> )}