From e51d4d3d71dde9aaae93b33940254b419fb713d5 Mon Sep 17 00:00:00 2001 From: Egor Date: Fri, 23 Jan 2026 03:35:27 +0300 Subject: [PATCH 1/4] Update Subscription.tsx --- src/pages/Subscription.tsx | 39 +++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/src/pages/Subscription.tsx b/src/pages/Subscription.tsx index e09fb50..2298c72 100644 --- a/src/pages/Subscription.tsx +++ b/src/pages/Subscription.tsx @@ -21,6 +21,20 @@ const getErrorMessage = (error: unknown): string => { return 'Произошла ошибка' } +// Helper to extract insufficient balance error details +const getInsufficientBalanceError = (error: unknown): { required: number; balance: number } | null => { + if (error instanceof AxiosError) { + const detail = error.response?.data?.detail + if (typeof detail === 'object' && detail?.code === 'insufficient_balance') { + return { + required: detail.required || 0, + balance: detail.balance || 0, + } + } + } + return null +} + // Icons const CopyIcon = () => ( @@ -742,11 +756,26 @@ export default function Subscription() { {/* Pause mutation error */} - {pauseMutation.isError && ( -
- {getErrorMessage(pauseMutation.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 ? ( From ccb84405c4d9b3fa88dc6d9c0f9296087279bf41 Mon Sep 17 00:00:00 2001 From: Egor Date: Fri, 23 Jan 2026 03:35:48 +0300 Subject: [PATCH 2/4] Add files via upload --- src/locales/en.json | 1 + src/locales/ru.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/locales/en.json b/src/locales/en.json index abf4758..df51eb8 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -216,6 +216,7 @@ "pausedMessage": "Subscription paused", "resumedMessage": "Subscription resumed", "dailyOnly": "Pause is only available for daily tariffs", + "insufficientBalance": "Insufficient balance to resume subscription", "pausedInfo": "Subscription paused", "pausedDescription": "Charges stopped. Subscription will be active until", "nextCharge": "Until next charge", diff --git a/src/locales/ru.json b/src/locales/ru.json index 8ece17f..f88820b 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -216,6 +216,7 @@ "pausedMessage": "Подписка приостановлена", "resumedMessage": "Подписка возобновлена", "dailyOnly": "Пауза доступна только для суточных тарифов", + "insufficientBalance": "Недостаточно средств для возобновления подписки", "pausedInfo": "Подписка приостановлена", "pausedDescription": "Списания остановлены. Подписка будет действовать до", "nextCharge": "До следующего списания", From 767b6669626c7e6f3a5bb942459f6c07d8453b0d Mon Sep 17 00:00:00 2001 From: Egor Date: Fri, 23 Jan 2026 03:39:08 +0300 Subject: [PATCH 3/4] Update Subscription.tsx --- src/pages/Subscription.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/pages/Subscription.tsx b/src/pages/Subscription.tsx index 2298c72..19d4109 100644 --- a/src/pages/Subscription.tsx +++ b/src/pages/Subscription.tsx @@ -2305,10 +2305,17 @@ export default function Subscription() {
{preview.discount_label}
)} - {!preview.can_purchase && preview.status_message && ( -
- {preview.status_message} -
+ {!preview.can_purchase && ( + preview.missing_amount_kopeks > 0 ? ( + + ) : preview.status_message ? ( +
+ {preview.status_message} +
+ ) : null )} ) : null} From 2fe3a0bb18b3cc62d3973de534cfafcdd7832d11 Mon Sep 17 00:00:00 2001 From: Egor Date: Fri, 23 Jan 2026 03:44:18 +0300 Subject: [PATCH 4/4] Update AdminTariffs.tsx --- src/pages/AdminTariffs.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/AdminTariffs.tsx b/src/pages/AdminTariffs.tsx index 30a4b10..2f72f8a 100644 --- a/src/pages/AdminTariffs.tsx +++ b/src/pages/AdminTariffs.tsx @@ -136,7 +136,7 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri const [name, setName] = useState(tariff?.name || '') const [description, setDescription] = useState(tariff?.description || '') - const [trafficLimitGb, setTrafficLimitGb] = useState(tariff?.traffic_limit_gb || 100) + const [trafficLimitGb, setTrafficLimitGb] = useState(tariff?.traffic_limit_gb ?? 100) const [deviceLimit, setDeviceLimit] = useState(tariff?.device_limit || 1) const [devicePriceKopeks, setDevicePriceKopeks] = useState(tariff?.device_price_kopeks || 0) const [maxDeviceLimit, setMaxDeviceLimit] = useState(tariff?.max_device_limit || 0) @@ -182,7 +182,7 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri device_price_kopeks: devicePriceKopeks > 0 ? devicePriceKopeks : undefined, max_device_limit: maxDeviceLimit > 0 ? maxDeviceLimit : undefined, tier_level: tierLevel, - period_prices: periodPrices.filter(p => p.price_kopeks > 0), + period_prices: periodPrices.filter(p => p.price_kopeks >= 0), allowed_squads: selectedSquads, traffic_topup_enabled: trafficTopupEnabled, traffic_topup_packages: trafficTopupPackages, @@ -757,7 +757,7 @@ function DailyTariffModal({ tariff, servers, onSave, onClose, isLoading }: Daily const [name, setName] = useState(tariff?.name || '') const [description, setDescription] = useState(tariff?.description || '') - const [trafficLimitGb, setTrafficLimitGb] = useState(tariff?.traffic_limit_gb || 100) + const [trafficLimitGb, setTrafficLimitGb] = useState(tariff?.traffic_limit_gb ?? 100) const [deviceLimit, setDeviceLimit] = useState(tariff?.device_limit || 1) const [devicePriceKopeks, setDevicePriceKopeks] = useState(tariff?.device_price_kopeks || 0) const [maxDeviceLimit, setMaxDeviceLimit] = useState(tariff?.max_device_limit || 0)