import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { Navigate, useNavigate, useParams } from 'react-router'; import { subscriptionApi } from '../api/subscription'; import { useTheme } from '../hooks/useTheme'; import { getGlassColors } from '../utils/glassTheme'; import { useCurrency } from '../hooks/useCurrency'; import { useHaptic } from '../platform'; import InsufficientBalancePrompt from '../components/InsufficientBalancePrompt'; import { WebBackButton } from '../components/WebBackButton'; export default function RenewSubscription() { const { subscriptionId } = useParams<{ subscriptionId: string }>(); const subId = subscriptionId ? Number(subscriptionId) : undefined; const { t } = useTranslation(); const navigate = useNavigate(); const queryClient = useQueryClient(); const { isDark } = useTheme(); const g = getGlassColors(isDark); const { formatAmount, currencySymbol } = useCurrency(); const { impact } = useHaptic(); const [selectedPeriod, setSelectedPeriod] = useState(null); const [error, setError] = useState(null); // Load subscription detail for tariff name const { data: subscriptionResponse } = useQuery({ queryKey: ['subscription', subId], queryFn: () => subscriptionApi.getSubscription(subId), enabled: !!subId, staleTime: 30_000, }); const subscription = subscriptionResponse?.subscription ?? null; // Load renewal options const { data: options, isLoading } = useQuery({ queryKey: ['renewal-options', subId], queryFn: () => subscriptionApi.getRenewalOptions(subId), enabled: !!subId, staleTime: 0, refetchOnMount: 'always', }); // Load balance const { data: purchaseOptions } = useQuery({ queryKey: ['purchase-options', subId], queryFn: () => subscriptionApi.getPurchaseOptions(subId), staleTime: 0, }); const balanceKopeks = purchaseOptions?.balance_kopeks ?? 0; const renewMutation = useMutation({ mutationFn: (periodDays: number) => subscriptionApi.renewSubscription(periodDays, subId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['subscription', subId] }); queryClient.invalidateQueries({ queryKey: ['subscriptions-list'] }); queryClient.invalidateQueries({ queryKey: ['renewal-options', subId] }); queryClient.invalidateQueries({ queryKey: ['balance'] }); navigate(`/subscriptions/${subId}`, { replace: true }); }, onError: (err: unknown) => { const detail = err && typeof err === 'object' && 'response' in err ? ((err as { response?: { data?: { detail?: unknown } } }).response?.data?.detail ?? null) : null; if (detail && typeof detail === 'object' && 'code' in (detail as Record)) { const typed = detail as { code: string; missing_amount?: number }; if (typed.code === 'insufficient_funds' && typed.missing_amount) { setError(`insufficient:${typed.missing_amount}`); return; } } setError(typeof detail === 'string' ? detail : t('common.error')); }, }); const handleRenew = (periodDays: number) => { impact('medium'); setError(null); renewMutation.mutate(periodDays); }; if (!subId) { return ; } if (isLoading) { return (
); } const insufficientMatch = error?.match(/^insufficient:(\d+)$/); const missingAmount = insufficientMatch ? Number(insufficientMatch[1]) : null; return (
{/* Title */}

{t('subscription.extend', 'Продлить подписку')}

{subscription?.tariff_name && (

{subscription.tariff_name}

)}
{/* Balance */}
{t('common.balance', 'Баланс')} {formatAmount(balanceKopeks / 100)} {currencySymbol}
{/* Period options */} {!options || options.length === 0 ? (

{t('subscription.noRenewalOptions', 'Нет доступных вариантов продления')}

) : (
{options.map((option) => { const isSelected = selectedPeriod === option.period_days; const canAfford = balanceKopeks >= option.price_kopeks; const months = Math.max(1, Math.round(option.period_days / 30)); const perMonth = option.price_kopeks / months; return ( ); })}
)} {/* Insufficient balance prompt */} {missingAmount && } {/* Error */} {error && !missingAmount && (
{error}
)} {/* Renew button */} {selectedPeriod && ( )}
); }