import { useTranslation } from 'react-i18next'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { subscriptionApi } from '../../../api/subscription'; import { getErrorMessage } from '../../../utils/subscriptionHelpers'; import InsufficientBalancePrompt from '../../InsufficientBalancePrompt'; import { ChevronRightIcon } from '../../icons'; import type { PurchaseOptions, Subscription } from '../../../types'; // ────────────────────────────────────────────────────────────────── // Buy-devices sheet. Self-owns its devicePrice query + purchase mutation; // parent only passes the subscription / id / open state and the shared // purchaseOptions (which it already holds for sibling sheets and balance // gating). // // Extracted from Subscription.tsx to drop ~190 lines from the god page. // ────────────────────────────────────────────────────────────────── export interface DeviceTopupSheetProps { open: boolean; onOpen: () => void; onClose: () => void; subscription: Subscription; subscriptionId: number | undefined; devicesToAdd: number; onDevicesToAddChange: (n: number) => void; purchaseOptions: PurchaseOptions | undefined; isDark: boolean; } export function DeviceTopupSheet({ open, onOpen, onClose, subscription, subscriptionId, devicesToAdd, onDevicesToAddChange, purchaseOptions, isDark, }: DeviceTopupSheetProps) { const { t } = useTranslation(); const queryClient = useQueryClient(); const formatPrice = (kopeks: number) => { const rubles = kopeks / 100; return rubles % 1 === 0 ? `${rubles} ₽` : `${rubles.toFixed(2)} ₽`; }; const { data: devicePriceData } = useQuery({ queryKey: ['device-price', devicesToAdd, subscriptionId], queryFn: () => subscriptionApi.getDevicePrice(devicesToAdd, subscriptionId), enabled: open && !!subscription, }); const devicePurchaseMutation = useMutation({ mutationFn: () => subscriptionApi.purchaseDevices(devicesToAdd, subscriptionId), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['subscription', subscriptionId] }); queryClient.invalidateQueries({ queryKey: ['subscriptions-list'] }); queryClient.invalidateQueries({ queryKey: ['devices', subscriptionId] }); queryClient.invalidateQueries({ queryKey: ['device-price'] }); queryClient.invalidateQueries({ queryKey: ['balance'] }); onClose(); onDevicesToAddChange(1); }, }); if (!open) { return ( ); } return (

{t('subscription.buyDevices')}

{devicePriceData?.available === false ? (
{devicePriceData.reason || t('subscription.additionalOptions.devicesUnavailable')}
) : (
{/* Device counter */}
{devicesToAdd}
{t('subscription.additionalOptions.devicesUnit')}
{devicePriceData?.max_device_limit && (
{t('subscription.additionalOptions.currentDeviceLimit', { count: devicePriceData.current_device_limit || subscription.device_limit, })}{' '} /{' '} {t('subscription.additionalOptions.maxDevices', { count: devicePriceData.max_device_limit, })}
)} {/* Price info */} {devicePriceData?.available && devicePriceData.price_per_device_label && (
{devicePriceData.discount_percent && devicePriceData.discount_percent > 0 && devicePriceData.original_price_per_device_kopeks ? ( {formatPrice(devicePriceData.original_price_per_device_kopeks)} {devicePriceData.price_per_device_label} ) : ( devicePriceData.price_per_device_label )} /{t('subscription.perDevice').replace('/ ', '')} ( {t('subscription.days', { count: devicePriceData.days_left })})
{devicePriceData.discount_percent && devicePriceData.discount_percent > 0 && (
-{devicePriceData.discount_percent}%
)} {devicePriceData.total_price_kopeks === 0 ? (
{t('subscription.switchTariff.free')}
) : (
{devicePriceData.discount_percent && devicePriceData.discount_percent > 0 && devicePriceData.base_total_price_kopeks && ( {formatPrice(devicePriceData.base_total_price_kopeks)} )} {devicePriceData.total_price_label}
)}
)} {/* Insufficient balance */} {devicePriceData?.available && purchaseOptions && devicePriceData.total_price_kopeks && devicePriceData.total_price_kopeks > purchaseOptions.balance_kopeks && ( { await subscriptionApi.saveDevicesCart(devicesToAdd, subscriptionId); }} /> )} {devicePurchaseMutation.isError && (
{getErrorMessage(devicePurchaseMutation.error)}
)}
)}
); }