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)}
)}
)}
);
}