{t('subscription.title')}
{/* Current Subscription */}
{subscription ? (
{t('subscription.currentPlan')}
{subscription.tariff_name && (
{subscription.tariff_name}
)}
{subscription.is_trial
? t('subscription.trialStatus')
: subscription.is_active
? t('subscription.active')
: t('subscription.expired')}
{/* Connection Data - Top Priority */}
{subscription.subscription_url && (
{t('subscription.connectionInfo')}
{/* Get Config Button */}
{/* Subscription URL - hidden when hide_subscription_link is true */}
{!subscription.hide_subscription_link && (
{subscription.subscription_url}
)}
)}
{t('subscription.daysLeft')}
{subscription.days_left > 0 ? (
t('subscription.days', { count: subscription.days_left })
) : subscription.hours_left > 0 ? (
`${t('subscription.hours', { count: subscription.hours_left })} ${t('subscription.minutes', { count: subscription.minutes_left })}`
) : subscription.minutes_left > 0 ? (
t('subscription.minutes', { count: subscription.minutes_left })
) : (
{t('subscription.expired')}
)}
{t('subscription.expiresAt')}
{new Date(subscription.end_date).toLocaleDateString()}
{t('subscription.traffic')}
{(trafficData?.traffic_used_gb ?? subscription.traffic_used_gb).toFixed(1)} /{' '}
{subscription.traffic_limit_gb || '∞'} GB
{t('subscription.devices')}
{subscription.device_limit}
{/* Servers */}
{subscription.servers && subscription.servers.length > 0 && (
{t('subscription.serversLabel')}
{subscription.servers.map((server) => (
{server.country_code && (
{getFlagEmoji(server.country_code)}
)}
{server.name}
))}
)}
{/* Traffic Usage */}
{subscription.traffic_limit_gb > 0 && (
{t('subscription.trafficUsed')}
{(trafficData?.traffic_used_percent ?? subscription.traffic_used_percent).toFixed(
1,
)}
%
)}
{/* Purchased Traffic Packages */}
{subscription.traffic_purchases && subscription.traffic_purchases.length > 0 && (
{t('subscription.purchasedTraffic')}
{subscription.traffic_purchases.map((purchase) => (
{purchase.traffic_gb} {t('common.units.gb')}
{purchase.days_remaining === 0 ? (
{t('subscription.expired')}
) : (
{t('subscription.days', { count: purchase.days_remaining })}
)}
{t('subscription.trafficResetAt')}:{' '}
{new Date(purchase.expires_at).toLocaleDateString(undefined, {
day: '2-digit',
month: '2-digit',
year: 'numeric',
})}
{new Date(purchase.created_at).toLocaleDateString()}
{new Date(purchase.expires_at).toLocaleDateString()}
))}
)}
{/* Autopay Toggle - hide for daily tariffs */}
{!subscription.is_trial && !subscription.is_daily && (
{t('subscription.autoRenewal')}
{t('subscription.daysBeforeExpiry', { count: subscription.autopay_days_before })}
)}
) : (
{t('subscription.noSubscription')}
)}
{/* Daily Subscription Pause */}
{subscription && subscription.is_daily && !subscription.is_trial && (
{t('subscription.pause.title')}
{subscription.is_daily_paused
? t('subscription.pause.paused')
: t('subscription.pause.active')}
{/* Pause mutation error */}
{pauseMutation.isError &&
(() => {
const balanceError = getInsufficientBalanceError(pauseMutation.error);
if (balanceError) {
const missingAmount = balanceError.required - balanceError.balance;
return (
);
}
return (
{getErrorMessage(pauseMutation.error)}
);
})()}
{/* Paused info or Next charge progress bar */}
{subscription.is_daily_paused ? (
⏸️
{t('subscription.pause.pausedInfo')}
{t('subscription.pause.pausedDescription')}{' '}
{new Date(subscription.end_date).toLocaleDateString()} (
{t('subscription.pause.days', { count: subscription.days_left })})
) : (
subscription.next_daily_charge_at &&
(() => {
const now = new Date();
// Backend returns UTC datetime, ensure it's parsed as UTC
const nextChargeStr = subscription.next_daily_charge_at.endsWith('Z')
? subscription.next_daily_charge_at
: subscription.next_daily_charge_at + 'Z';
const nextCharge = new Date(nextChargeStr);
const totalMs = 24 * 60 * 60 * 1000; // 24 hours in ms
const remainingMs = Math.max(0, nextCharge.getTime() - now.getTime());
const elapsedMs = totalMs - remainingMs;
const progress = Math.min(100, (elapsedMs / totalMs) * 100);
const hours = Math.floor(remainingMs / (1000 * 60 * 60));
const minutes = Math.floor((remainingMs % (1000 * 60 * 60)) / (1000 * 60));
return (
{t('subscription.pause.nextCharge')}
{hours > 0
? `${hours}${t('subscription.pause.hours')} ${minutes}${t('subscription.pause.minutes')}`
: `${minutes}${t('subscription.pause.minutes')}`}
{subscription.daily_price_kopeks && (
{t('subscription.pause.willBeCharged')}:{' '}
{formatPrice(subscription.daily_price_kopeks)}
)}
);
})()
)}
)}
{/* Additional Options (Buy Devices) */}
{subscription && subscription.is_active && !subscription.is_trial && (
{t('subscription.additionalOptions.title')}
{/* Buy Devices */}
{!showDeviceTopup ? (
) : (
{t('subscription.buyDevices')}
{/* Check if completely unavailable (no subscription, price not set, etc.) */}
{devicePriceData?.available === false && !devicePriceData?.max_device_limit ? (
{devicePriceData.reason || t('subscription.additionalOptions.devicesUnavailable')}
) : (
{/* Device selector - show even at max limit */}
{devicesToAdd}
{t('subscription.additionalOptions.devicesUnit')}
{/* Show limit info when at or near max */}
{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,
})}
)}
{/* Show reason if can't add requested amount */}
{devicePriceData?.available === false && devicePriceData?.reason && (
{devicePriceData.reason}
)}
{/* Price info - only when available */}
{devicePriceData?.available && devicePriceData.price_per_device_label && (
{devicePriceData.price_per_device_label}/
{t('subscription.perDevice').replace('/ ', '')} (
{t('subscription.days', { count: devicePriceData.days_left })})
{devicePriceData.total_price_label}
)}
{devicePriceData?.available &&
purchaseOptions &&
devicePriceData.total_price_kopeks &&
devicePriceData.total_price_kopeks > purchaseOptions.balance_kopeks && (
{
await subscriptionApi.saveDevicesCart(devicesToAdd);
}}
/>
)}
{devicePurchaseMutation.isError && (
{getErrorMessage(devicePurchaseMutation.error)}
)}
)}
)}
{/* Buy Traffic */}
{subscription.traffic_limit_gb > 0 && (
{!showTrafficTopup ? (
) : (
{t('subscription.additionalOptions.buyTrafficTitle')}
⚠️ {t('subscription.additionalOptions.trafficWarning')}
{!trafficPackages || trafficPackages.length === 0 ? (
{t('subscription.additionalOptions.trafficUnavailable')}
) : (
{trafficPackages.map((pkg) => (
))}
{selectedTrafficPackage &&
(() => {
const selectedPkg = trafficPackages.find(
(p) => p.gb === selectedTrafficPackage,
);
const hasEnoughBalance =
!selectedPkg ||
!purchaseOptions ||
selectedPkg.price_kopeks <= purchaseOptions.balance_kopeks;
const missingAmount =
selectedPkg && purchaseOptions
? selectedPkg.price_kopeks - purchaseOptions.balance_kopeks
: 0;
return (
<>
{!hasEnoughBalance && missingAmount > 0 && (
{
await subscriptionApi.saveTrafficCart(selectedTrafficPackage);
}}
/>
)}
>
);
})()}
{trafficPurchaseMutation.isError && (
{getErrorMessage(trafficPurchaseMutation.error)}
)}
)}
)}
)}
{/* Server Management - only in classic mode */}
{!isTariffsMode && (
{!showServerManagement ? (
) : (
{t('subscription.additionalOptions.manageServersTitle')}
{countriesLoading ? (
) : countriesData && countriesData.countries.length > 0 ? (
{t('subscription.serverManagement.statusLegend')}
{countriesData.discount_percent > 0 && (
🎁{' '}
{t('subscription.serverManagement.discountBanner', {
percent: countriesData.discount_percent,
})}
)}
{countriesData.countries.map((country) => {
const isCurrentlyConnected = country.is_connected;
const isSelected = selectedServersToUpdate.includes(country.uuid);
const willBeAdded = !isCurrentlyConnected && isSelected;
const willBeRemoved = isCurrentlyConnected && !isSelected;
return (
);
})}
{(() => {
const currentConnected = countriesData.countries
.filter((c) => c.is_connected)
.map((c) => c.uuid);
const added = selectedServersToUpdate.filter(
(u) => !currentConnected.includes(u),
);
const removed = currentConnected.filter(
(u) => !selectedServersToUpdate.includes(u),
);
const hasChanges = added.length > 0 || removed.length > 0;
// Calculate cost for added servers
const addedServers = countriesData.countries.filter((c) =>
added.includes(c.uuid),
);
const totalCost = addedServers.reduce((sum, s) => sum + s.price_kopeks, 0);
const hasEnoughBalance =
!purchaseOptions || totalCost <= purchaseOptions.balance_kopeks;
const missingAmount = purchaseOptions
? totalCost - purchaseOptions.balance_kopeks
: 0;
return hasChanges ? (
{added.length > 0 && (
{t('subscription.serverManagement.toAdd')}
{' '}
{addedServers.map((s) => s.name).join(', ')}
)}
{removed.length > 0 && (
{t('subscription.serverManagement.toDisconnect')}
{' '}
{countriesData.countries
.filter((c) => removed.includes(c.uuid))
.map((s) => s.name)
.join(', ')}
)}
{totalCost > 0 && (
{t('subscription.serverManagement.paymentProrated')}
{formatPrice(totalCost)}
)}
{totalCost > 0 && !hasEnoughBalance && missingAmount > 0 && (
)}
) : (
{t('subscription.serverManagement.selectServersHint')}
);
})()}
{updateCountriesMutation.isError && (
{getErrorMessage(updateCountriesMutation.error)}
)}
) : (
{t('subscription.serverManagement.noServersAvailable')}
)}
)}
)}
)}
{/* My Devices Section */}
{subscription && (
{t('subscription.myDevices')}
{devicesData && devicesData.devices.length > 0 && (
)}
{devicesLoading ? (
) : devicesData && devicesData.devices.length > 0 ? (
{devicesData.total} /{' '}
{t('subscription.devices', { count: devicesData.device_limit })}
{devicesData.devices.map((device) => (
{device.device_model || device.platform}
{device.platform}
))}
) : (
{t('subscription.noDevices')}
)}
)}
{/* Tariffs Section - Combined Purchase/Extend/Switch like MiniApp */}
{isTariffsMode && tariffs.length > 0 && (
{subscription?.is_daily && !subscription?.is_trial
? t('subscription.switchTariff.title')
: subscription && !subscription.is_trial
? t('subscription.extend')
: t('subscription.getSubscription')}
{/* Legacy subscription notice - if user has subscription without tariff */}
{subscription && !subscription.is_trial && !subscription.tariff_id && (
📦 {t('subscription.legacy.selectTariffTitle')}
{t('subscription.legacy.selectTariffDescription')}
⚠️ {t('subscription.legacy.currentSubContinues')}
)}
{/* Switch Tariff Preview Modal */}
{switchTariffId && (
{t('subscription.switchTariff.title')}
{switchPreviewLoading ? (
) : (
switchPreview &&
(() => {
// Find the target tariff to get daily price info
const targetTariff = tariffs.find((t) => t.id === switchTariffId);
const dailyPrice =
targetTariff?.daily_price_kopeks ?? targetTariff?.price_per_day_kopeks ?? 0;
const isDailyTariff = dailyPrice > 0;
return (
<>
{t('subscription.switchTariff.currentTariff')}
{switchPreview.current_tariff_name || '-'}
{t('subscription.switchTariff.newTariff')}
{switchPreview.new_tariff_name}
{t('subscription.switchTariff.remainingDays')}
{switchPreview.remaining_days}
{/* Daily tariff info */}
{isDailyTariff && (
{t('subscription.switchTariff.dailyPayment')}
{formatPrice(dailyPrice)}
{t('subscription.switchTariff.dailyChargeDescription')}
)}
{t('subscription.switchTariff.upgradeCost')}
{switchPreview.upgrade_cost_kopeks > 0
? switchPreview.upgrade_cost_label
: t('subscription.switchTariff.free')}
{!switchPreview.has_enough_balance &&
switchPreview.upgrade_cost_kopeks > 0 && (
)}
>
);
})()
)}
)}
{!showTariffPurchase ? (
<>
{/* Promo group discount banner */}
{tariffs.some((t) => t.promo_group_name) && (
{t('subscription.promoGroup.yourGroup', {
name: tariffs.find((t) => t.promo_group_name)?.promo_group_name,
})}
{t('subscription.promoGroup.personalDiscountsApplied')}
)}
{/* Tariff List - current tariff first */}
{[...tariffs]
// Hide Trial tariffs for users who already have trial subscription
.filter((tariff) => {
if (subscription?.is_trial && tariff.name.toLowerCase().includes('trial')) {
return false;
}
return true;
})
.sort((a, b) => {
const aIsCurrent = a.is_current || a.id === subscription?.tariff_id;
const bIsCurrent = b.is_current || b.id === subscription?.tariff_id;
if (aIsCurrent && !bIsCurrent) return -1;
if (!aIsCurrent && bIsCurrent) return 1;
return 0;
})
.map((tariff) => {
const isCurrentTariff =
tariff.is_current || tariff.id === subscription?.tariff_id;
const canSwitch =
subscription &&
subscription.tariff_id &&
!isCurrentTariff &&
!subscription.is_trial;
// Если есть подписка БЕЗ tariff_id (классическая) - разрешить выбрать тариф
const isLegacySubscription =
subscription && !subscription.is_trial && !subscription.tariff_id;
return (
{tariff.name}
{tariff.description && (
{tariff.description}
)}
{isCurrentTariff && (
{t('subscription.currentTariff')}
)}
{tariff.traffic_limit_label}
{t('subscription.devices', { count: tariff.device_limit })}
{t('subscription.servers', { count: tariff.servers_count })}
{/* Price info - daily or period-based */}
{(() => {
// Daily tariff price (is_daily + daily_price_kopeks)
const dailyPrice =
tariff.daily_price_kopeks ?? tariff.price_per_day_kopeks ?? 0;
const originalDailyPrice = tariff.original_daily_price_kopeks || 0;
const hasExistingDailyDiscount = originalDailyPrice > dailyPrice;
if (dailyPrice > 0) {
// Apply promo discount if no existing discount
const promoDaily = applyPromoDiscount(
dailyPrice,
hasExistingDailyDiscount,
);
return (
{formatPrice(promoDaily.price)}
{/* Show original price from promo group or promo offer */}
{(hasExistingDailyDiscount || promoDaily.original) && (
{formatPrice(
hasExistingDailyDiscount
? originalDailyPrice
: promoDaily.original!,
)}
)}
{t('subscription.tariff.perDay')}
{/* Show discount badge */}
{tariff.daily_discount_percent &&
tariff.daily_discount_percent > 0 ? (
-{tariff.daily_discount_percent}%
) : (
promoDaily.percent && (
-{promoDaily.percent}%
)
)}
);
}
// Period-based price
if (tariff.periods.length > 0) {
const firstPeriod = tariff.periods[0];
const hasExistingDiscount = !!(
firstPeriod?.original_price_kopeks &&
firstPeriod.original_price_kopeks > firstPeriod.price_kopeks
);
// Apply promo discount if no existing discount
const promoPeriod = applyPromoDiscount(
firstPeriod?.price_kopeks || 0,
hasExistingDiscount,
);
return (
{t('subscription.from')}
{formatPrice(promoPeriod.price)}
{/* Show original price from promo group or promo offer */}
{(hasExistingDiscount || promoPeriod.original) && (
{formatPrice(
hasExistingDiscount
? firstPeriod.original_price_kopeks!
: promoPeriod.original!,
)}
)}
{/* Show discount badge */}
{hasExistingDiscount && firstPeriod.discount_percent ? (
-{firstPeriod.discount_percent}%
) : (
promoPeriod.percent && (
-{promoPeriod.percent}%
)
)}
);
}
// Fallback
return (
{t('subscription.tariff.flexiblePayment')}
);
})()}
{/* Action Buttons */}
{isCurrentTariff ? (
/* Current tariff - extend button (hide for daily tariffs) */
subscription?.is_daily ? (
{t('subscription.currentTariff')}
) : (
)
) : isLegacySubscription ? (
/* Legacy subscription without tariff - allow selecting tariff for renewal */
) : canSwitch ? (
/* Other tariffs with existing tariff - switch button */
) : (
/* No subscription or trial - purchase button */
)}
);
})}
>
) : (
selectedTariff && (
/* Tariff Purchase Form */
{selectedTariff.name}
{/* Tariff Info */}
{t('subscription.traffic')}:
{selectedTariff.traffic_limit_label}
{t('subscription.devices')}:
{selectedTariff.device_limit}
{selectedTariff.extra_devices_count > 0 && (
(+{selectedTariff.extra_devices_count})
)}
{t('subscription.serversLabel')}:
{selectedTariff.servers_count}
{selectedTariff.servers.length > 0 && (
{selectedTariff.servers.map((server) => (
{server.name}
))}
{selectedTariff.servers_count > selectedTariff.servers.length && (
+{selectedTariff.servers_count - selectedTariff.servers.length}
)}
)}
{/* Daily Tariff Purchase */}
{selectedTariff.is_daily ||
(selectedTariff.daily_price_kopeks && selectedTariff.daily_price_kopeks > 0) ? (
{t('subscription.dailyPurchase.costPerDay')}
{formatPrice(selectedTariff.daily_price_kopeks || 0)}
•
{t('subscription.dailyPurchase.chargedDaily')}
•
{t('subscription.dailyPurchase.canPause')}
•
{t('subscription.dailyPurchase.pausedOnLowBalance')}
{/* Purchase button for daily tariff */}
{(() => {
const dailyPrice = selectedTariff.daily_price_kopeks || 0;
const hasEnoughBalance =
purchaseOptions && dailyPrice <= purchaseOptions.balance_kopeks;
return (
{purchaseOptions && !hasEnoughBalance && (
)}
{tariffPurchaseMutation.isError &&
!getInsufficientBalanceError(tariffPurchaseMutation.error) && (
{getErrorMessage(tariffPurchaseMutation.error)}
)}
{tariffPurchaseMutation.isError &&
getInsufficientBalanceError(tariffPurchaseMutation.error) && (
)}
);
})()}
) : (
<>
{/* Period Selection for non-daily tariffs */}
{t('subscription.selectPeriod')}
{/* Fixed periods */}
{selectedTariff.periods.length > 0 && !useCustomDays && (
{selectedTariff.periods.map((period) => {
const hasExistingDiscount = !!(
period.original_price_kopeks &&
period.original_price_kopeks > period.price_kopeks
);
const promoPeriod = applyPromoDiscount(
period.price_kopeks,
hasExistingDiscount,
);
const displayDiscount = hasExistingDiscount
? period.discount_percent
: promoPeriod.percent;
const displayOriginal = hasExistingDiscount
? period.original_price_kopeks
: promoPeriod.original;
const displayPrice = promoPeriod.price;
const displayPerMonth = hasExistingDiscount
? period.price_per_month_kopeks
: Math.round(promoPeriod.price / (period.days / 30));
return (
);
})}
)}
{/* Custom days option */}
{selectedTariff.custom_days_enabled &&
(selectedTariff.price_per_day_kopeks ?? 0) > 0 && (
{t('subscription.customDays.title')}
{useCustomDays && (
)}
)}
{/* Custom traffic option */}
{selectedTariff.custom_traffic_enabled &&
(selectedTariff.traffic_price_per_gb_kopeks ?? 0) > 0 && (
{t('subscription.customTraffic.label')}
{t('subscription.customTraffic.selectVolume')}
{!useCustomTraffic && (
{t('subscription.customTraffic.default', {
label: selectedTariff.traffic_limit_label,
})}
)}
{useCustomTraffic && (
{customTrafficGb} {t('common.units.gb')} ×{' '}
{formatPrice(selectedTariff.traffic_price_per_gb_kopeks ?? 0)}/
{t('common.units.gb')}
+
{formatPrice(
customTrafficGb *
(selectedTariff.traffic_price_per_gb_kopeks ?? 0),
)}
)}
)}
{/* Summary & Purchase */}
{(selectedTariffPeriod || useCustomDays) && (
{(() => {
// Calculate prices with promo discount
const basePeriodPrice = useCustomDays
? customDays * (selectedTariff.price_per_day_kopeks ?? 0)
: selectedTariffPeriod?.price_kopeks || 0;
const hasExistingPeriodDiscount =
!useCustomDays && selectedTariffPeriod?.original_price_kopeks
? selectedTariffPeriod.original_price_kopeks >
selectedTariffPeriod.price_kopeks
: false;
const promoPeriod = applyPromoDiscount(
basePeriodPrice,
hasExistingPeriodDiscount,
);
const trafficPrice =
useCustomTraffic && selectedTariff.custom_traffic_enabled
? customTrafficGb * (selectedTariff.traffic_price_per_gb_kopeks ?? 0)
: 0;
const totalPrice = promoPeriod.price + trafficPrice;
const originalTotal = promoPeriod.original
? promoPeriod.original + trafficPrice
: null;
return (
<>
{/* Price breakdown */}
{useCustomDays ? (
{t('subscription.stepPeriod')}:{' '}
{t('subscription.days', { count: customDays })}
{formatPrice(promoPeriod.price)}
{promoPeriod.original && (
{formatPrice(promoPeriod.original)}
)}
) : (
selectedTariffPeriod && (
<>
{/* Если есть доп. устройства - показываем разбивку */}
{(selectedTariffPeriod.extra_devices_count ?? 0) > 0 &&
selectedTariffPeriod.base_tariff_price_kopeks ? (
<>
{t('subscription.baseTariff')}:{' '}
{selectedTariffPeriod.label}
{formatPrice(
selectedTariffPeriod.base_tariff_price_kopeks,
)}
{t('subscription.extraDevices')} (
{selectedTariffPeriod.extra_devices_count})
+
{formatPrice(
selectedTariffPeriod.extra_devices_cost_kopeks ?? 0,
)}
>
) : (
{t('subscription.summary.period', {
label: selectedTariffPeriod.label,
})}
{formatPrice(promoPeriod.price)}
{(hasExistingPeriodDiscount ||
promoPeriod.original) && (
{formatPrice(
hasExistingPeriodDiscount
? selectedTariffPeriod.original_price_kopeks!
: promoPeriod.original!,
)}
)}
)}
>
)
)}
{useCustomTraffic && selectedTariff.custom_traffic_enabled && (
{t('subscription.summary.traffic', { gb: customTrafficGb })}
+{formatPrice(trafficPrice)}
)}
{/* Promo discount info */}
{promoPeriod.percent && (
{t('promo.discountApplied')} -{promoPeriod.percent}%
)}
{t('subscription.total')}
{formatPrice(totalPrice)}
{originalTotal && (
{formatPrice(originalTotal)}
)}
>
);
})()}
{tariffPurchaseMutation.isError &&
!getInsufficientBalanceError(tariffPurchaseMutation.error) && (
{getErrorMessage(tariffPurchaseMutation.error)}
)}
{tariffPurchaseMutation.isError &&
getInsufficientBalanceError(tariffPurchaseMutation.error) && (
)}
)}
>
)}
)
)}
)}
{/* Purchase/Extend Section - Classic Mode */}
{classicOptions && classicOptions.periods.length > 0 && (
{subscription && !subscription.is_trial
? t('subscription.extend')
: t('subscription.getSubscription')}
{!showPurchaseForm && (
)}
{showPurchaseForm && (
{/* Step Indicator */}
{t('subscription.step', { current: currentStepIndex + 1, total: steps.length })}
{steps.map((step, idx) => (
))}
{getStepLabel(currentStep)}
{/* Step: Period Selection */}
{currentStep === 'period' && classicOptions && (
{classicOptions.periods.map((period) => {
const hasExistingDiscount = !!(
period.discount_percent && period.discount_percent > 0
);
const promoPeriod = applyPromoDiscount(
period.price_kopeks,
hasExistingDiscount,
);
const displayDiscount = hasExistingDiscount
? period.discount_percent
: promoPeriod.percent;
const displayOriginal = hasExistingDiscount
? period.original_price_kopeks
: promoPeriod.original;
return (
);
})}
)}
{/* Step: Traffic Selection */}
{currentStep === 'traffic' && selectedPeriod?.traffic.options && (
{selectedPeriod.traffic.options.map((option) => {
const hasExistingDiscount = !!(
option.discount_percent && option.discount_percent > 0
);
const promoTraffic = applyPromoDiscount(
option.price_kopeks,
hasExistingDiscount,
);
return (
);
})}
)}
{/* Step: Server Selection */}
{currentStep === 'servers' && selectedPeriod?.servers.options && (
{selectedPeriod.servers.options
// Hide Trial server for users who already have trial subscription
.filter((server) => {
if (subscription?.is_trial && server.name.toLowerCase().includes('trial')) {
return false;
}
return true;
})
.map((server) => {
const hasExistingDiscount = !!(
server.discount_percent && server.discount_percent > 0
);
const promoServer = applyPromoDiscount(
server.price_kopeks,
hasExistingDiscount,
);
return (
);
})}
)}
{/* Step: Device Selection */}
{currentStep === 'devices' && selectedPeriod && (
{selectedDevices}
{t('subscription.devices')}
{t('subscription.devicesFree', { count: selectedPeriod.devices.min })}
{selectedPeriod.devices.max > selectedPeriod.devices.min && (
{formatPrice(selectedPeriod.devices.price_per_device_kopeks)}{' '}
{t('subscription.perExtraDevice')}
)}
)}
{/* Step: Confirm */}
{currentStep === 'confirm' && (
{previewLoading ? (
) : preview ? (
{/* Active promo discount banner */}
{activeDiscount?.is_active &&
activeDiscount.discount_percent &&
!preview.original_price_kopeks && (
{t('promo.discountApplied')} -{activeDiscount.discount_percent}%
)}
{preview.breakdown.map((item, idx) => (
{item.label}
{item.value}
))}
{(() => {
// Apply promo discount if not already applied by server
const hasServerDiscount = !!preview.original_price_kopeks;
const promoTotal = applyPromoDiscount(
preview.total_price_kopeks,
hasServerDiscount,
);
const displayTotal = promoTotal.price;
const displayOriginal = hasServerDiscount
? preview.original_price_kopeks
: promoTotal.original;
return (
{t('subscription.total')}
{formatPrice(displayTotal)}
{displayOriginal && (
{formatPrice(displayOriginal)}
)}
);
})()}
{preview.discount_label && (
{preview.discount_label}
)}
{!preview.can_purchase &&
(preview.missing_amount_kopeks > 0 ? (
) : preview.status_message ? (
{preview.status_message}
) : null)}
) : null}
)}
{/* Navigation Buttons */}
{!isFirstStep && (
)}
{isFirstStep && (
)}
{!isLastStep ? (
) : (
)}
{purchaseMutation.isError && (
{getErrorMessage(purchaseMutation.error)}
)}
)}
)}
{/* Connection Modal */}
{showConnectionModal &&
setShowConnectionModal(false)} />}
);
}